array.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  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. #include <ext/spl/spl_iterators.h>
  31. #include <Zend/zend_API.h>
  32. #include <Zend/zend_interfaces.h>
  33. #include "protobuf.h"
  34. ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1)
  35. ZEND_ARG_INFO(0, index)
  36. ZEND_END_ARG_INFO()
  37. ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2)
  38. ZEND_ARG_INFO(0, index)
  39. ZEND_ARG_INFO(0, newval)
  40. ZEND_END_ARG_INFO()
  41. ZEND_BEGIN_ARG_INFO(arginfo_void, 0)
  42. ZEND_END_ARG_INFO()
  43. static zend_function_entry repeated_field_methods[] = {
  44. PHP_ME(RepeatedField, __construct, NULL, ZEND_ACC_PUBLIC)
  45. PHP_ME(RepeatedField, append, NULL, ZEND_ACC_PUBLIC)
  46. PHP_ME(RepeatedField, offsetExists, arginfo_offsetGet, ZEND_ACC_PUBLIC)
  47. PHP_ME(RepeatedField, offsetGet, arginfo_offsetGet, ZEND_ACC_PUBLIC)
  48. PHP_ME(RepeatedField, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC)
  49. PHP_ME(RepeatedField, offsetUnset, arginfo_offsetGet, ZEND_ACC_PUBLIC)
  50. PHP_ME(RepeatedField, count, arginfo_void, ZEND_ACC_PUBLIC)
  51. PHP_ME(RepeatedField, getIterator, arginfo_void, ZEND_ACC_PUBLIC)
  52. ZEND_FE_END
  53. };
  54. static zend_function_entry repeated_field_iter_methods[] = {
  55. PHP_ME(RepeatedFieldIter, rewind, arginfo_void, ZEND_ACC_PUBLIC)
  56. PHP_ME(RepeatedFieldIter, current, arginfo_void, ZEND_ACC_PUBLIC)
  57. PHP_ME(RepeatedFieldIter, key, arginfo_void, ZEND_ACC_PUBLIC)
  58. PHP_ME(RepeatedFieldIter, next, arginfo_void, ZEND_ACC_PUBLIC)
  59. PHP_ME(RepeatedFieldIter, valid, arginfo_void, ZEND_ACC_PUBLIC)
  60. ZEND_FE_END
  61. };
  62. // Forward declare static functions.
  63. static int repeated_field_array_init(zval *array, upb_fieldtype_t type,
  64. uint size ZEND_FILE_LINE_DC);
  65. static void repeated_field_write_dimension(zval *object, zval *offset,
  66. zval *value TSRMLS_DC);
  67. static int repeated_field_has_dimension(zval *object, zval *offset TSRMLS_DC);
  68. static HashTable *repeated_field_get_gc(zval *object, CACHED_VALUE **table,
  69. int *n TSRMLS_DC);
  70. #if PHP_MAJOR_VERSION < 7
  71. static zend_object_value repeated_field_create(zend_class_entry *ce TSRMLS_DC);
  72. static zend_object_value repeated_field_iter_create(zend_class_entry *ce TSRMLS_DC);
  73. #else
  74. static zend_object *repeated_field_create(zend_class_entry *ce TSRMLS_DC);
  75. static zend_object *repeated_field_iter_create(zend_class_entry *ce TSRMLS_DC);
  76. #endif
  77. // -----------------------------------------------------------------------------
  78. // RepeatedField creation/desctruction
  79. // -----------------------------------------------------------------------------
  80. zend_class_entry* repeated_field_type;
  81. zend_class_entry* repeated_field_iter_type;
  82. zend_object_handlers* repeated_field_handlers;
  83. zend_object_handlers* repeated_field_iter_handlers;
  84. // Define object free method.
  85. PHP_PROTO_OBJECT_FREE_START(RepeatedField, repeated_field)
  86. #if PHP_MAJOR_VERSION < 7
  87. php_proto_zval_ptr_dtor(intern->array);
  88. #else
  89. php_proto_zval_ptr_dtor(&intern->array);
  90. #endif
  91. PHP_PROTO_OBJECT_FREE_END
  92. PHP_PROTO_OBJECT_DTOR_START(RepeatedField, repeated_field)
  93. PHP_PROTO_OBJECT_DTOR_END
  94. // Define object create method.
  95. PHP_PROTO_OBJECT_CREATE_START(RepeatedField, repeated_field)
  96. #if PHP_MAJOR_VERSION < 7
  97. intern->array = NULL;
  98. #endif
  99. intern->type = 0;
  100. intern->msg_ce = NULL;
  101. PHP_PROTO_OBJECT_CREATE_END(RepeatedField, repeated_field)
  102. // Init class entry.
  103. PHP_PROTO_INIT_CLASS_START("Google\\Protobuf\\Internal\\RepeatedField",
  104. RepeatedField, repeated_field)
  105. zend_class_implements(repeated_field_type TSRMLS_CC, 3, spl_ce_ArrayAccess,
  106. zend_ce_aggregate, spl_ce_Countable);
  107. repeated_field_handlers->write_dimension = repeated_field_write_dimension;
  108. repeated_field_handlers->get_gc = repeated_field_get_gc;
  109. PHP_PROTO_INIT_CLASS_END
  110. // Define array element free function.
  111. #if PHP_MAJOR_VERSION < 7
  112. static inline void php_proto_array_string_release(void *value) {
  113. zval_ptr_dtor(value);
  114. }
  115. static inline void php_proto_array_object_release(void *value) {
  116. zval_ptr_dtor(value);
  117. }
  118. static inline void php_proto_array_default_release(void *value) {
  119. }
  120. #else
  121. static inline void php_proto_array_string_release(zval *value) {
  122. void* ptr = Z_PTR_P(value);
  123. zend_string* object = *(zend_string**)ptr;
  124. zend_string_release(object);
  125. efree(ptr);
  126. }
  127. static inline void php_proto_array_object_release(zval *value) {
  128. zval_ptr_dtor(value);
  129. }
  130. static void php_proto_array_default_release(zval* value) {
  131. void* ptr = Z_PTR_P(value);
  132. efree(ptr);
  133. }
  134. #endif
  135. static int repeated_field_array_init(zval *array, upb_fieldtype_t type,
  136. uint size ZEND_FILE_LINE_DC) {
  137. PHP_PROTO_ALLOC_ARRAY(array);
  138. switch (type) {
  139. case UPB_TYPE_STRING:
  140. case UPB_TYPE_BYTES:
  141. zend_hash_init(Z_ARRVAL_P(array), size, NULL,
  142. php_proto_array_string_release, 0);
  143. break;
  144. case UPB_TYPE_MESSAGE:
  145. zend_hash_init(Z_ARRVAL_P(array), size, NULL,
  146. php_proto_array_object_release, 0);
  147. break;
  148. default:
  149. zend_hash_init(Z_ARRVAL_P(array), size, NULL,
  150. php_proto_array_default_release, 0);
  151. }
  152. return SUCCESS;
  153. }
  154. // -----------------------------------------------------------------------------
  155. // RepeatedField Handlers
  156. // -----------------------------------------------------------------------------
  157. static void repeated_field_write_dimension(zval *object, zval *offset,
  158. zval *value TSRMLS_DC) {
  159. uint64_t index;
  160. RepeatedField *intern = UNBOX(RepeatedField, object);
  161. HashTable *ht = PHP_PROTO_HASH_OF(intern->array);
  162. int size = native_slot_size(intern->type);
  163. unsigned char memory[NATIVE_SLOT_MAX_SIZE];
  164. memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
  165. if (!native_slot_set_by_array(intern->type, intern->msg_ce, memory,
  166. value TSRMLS_CC)) {
  167. return;
  168. }
  169. if (!offset || Z_TYPE_P(offset) == IS_NULL) {
  170. index = zend_hash_num_elements(PHP_PROTO_HASH_OF(intern->array));
  171. } else {
  172. if (protobuf_convert_to_uint64(offset, &index)) {
  173. if (!zend_hash_index_exists(ht, index)) {
  174. zend_error(E_USER_ERROR, "Element at %llu doesn't exist.\n",
  175. (long long unsigned int)index);
  176. return;
  177. }
  178. } else {
  179. return;
  180. }
  181. }
  182. if (intern->type == UPB_TYPE_MESSAGE) {
  183. php_proto_zend_hash_index_update_zval(ht, index, *(zval**)memory);
  184. } else {
  185. php_proto_zend_hash_index_update_mem(ht, index, memory, size, NULL);
  186. }
  187. }
  188. #if PHP_MAJOR_VERSION < 7
  189. static HashTable *repeated_field_get_gc(zval *object, zval ***table,
  190. int *n TSRMLS_DC) {
  191. #else
  192. static HashTable *repeated_field_get_gc(zval *object, zval **table, int *n) {
  193. #endif
  194. *table = NULL;
  195. *n = 0;
  196. RepeatedField *intern = UNBOX(RepeatedField, object);
  197. return PHP_PROTO_HASH_OF(intern->array);
  198. }
  199. // -----------------------------------------------------------------------------
  200. // C RepeatedField Utilities
  201. // -----------------------------------------------------------------------------
  202. void *repeated_field_index_native(RepeatedField *intern, int index TSRMLS_DC) {
  203. HashTable *ht = PHP_PROTO_HASH_OF(intern->array);
  204. void *value;
  205. if (intern->type == UPB_TYPE_MESSAGE) {
  206. if (php_proto_zend_hash_index_find_zval(ht, index, (void **)&value) ==
  207. FAILURE) {
  208. zend_error(E_USER_ERROR, "Element at %d doesn't exist.\n", index);
  209. return NULL;
  210. }
  211. } else {
  212. if (php_proto_zend_hash_index_find_mem(ht, index, (void **)&value) ==
  213. FAILURE) {
  214. zend_error(E_USER_ERROR, "Element at %d doesn't exist.\n", index);
  215. return NULL;
  216. }
  217. }
  218. return value;
  219. }
  220. void repeated_field_push_native(RepeatedField *intern, void *value) {
  221. HashTable *ht = PHP_PROTO_HASH_OF(intern->array);
  222. int size = native_slot_size(intern->type);
  223. if (intern->type == UPB_TYPE_MESSAGE) {
  224. php_proto_zend_hash_next_index_insert_zval(ht, value);
  225. } else {
  226. php_proto_zend_hash_next_index_insert_mem(ht, (void **)value, size, NULL);
  227. }
  228. }
  229. void repeated_field_ensure_created(
  230. const upb_fielddef *field,
  231. CACHED_VALUE *repeated_field PHP_PROTO_TSRMLS_DC) {
  232. if (ZVAL_IS_NULL(CACHED_PTR_TO_ZVAL_PTR(repeated_field))) {
  233. zval_ptr_dtor(repeated_field);
  234. #if PHP_MAJOR_VERSION < 7
  235. MAKE_STD_ZVAL(CACHED_PTR_TO_ZVAL_PTR(repeated_field));
  236. #endif
  237. repeated_field_create_with_field(repeated_field_type, field,
  238. repeated_field PHP_PROTO_TSRMLS_CC);
  239. }
  240. }
  241. void repeated_field_create_with_field(
  242. zend_class_entry *ce, const upb_fielddef *field,
  243. CACHED_VALUE *repeated_field PHP_PROTO_TSRMLS_DC) {
  244. upb_fieldtype_t type = upb_fielddef_type(field);
  245. const zend_class_entry *msg_ce = field_type_class(field PHP_PROTO_TSRMLS_CC);
  246. repeated_field_create_with_type(ce, type, msg_ce,
  247. repeated_field PHP_PROTO_TSRMLS_CC);
  248. }
  249. void repeated_field_create_with_type(
  250. zend_class_entry *ce, upb_fieldtype_t type, const zend_class_entry *msg_ce,
  251. CACHED_VALUE *repeated_field PHP_PROTO_TSRMLS_DC) {
  252. CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(CACHED_PTR_TO_ZVAL_PTR(repeated_field),
  253. repeated_field_type);
  254. RepeatedField *intern =
  255. UNBOX(RepeatedField, CACHED_TO_ZVAL_PTR(*repeated_field));
  256. intern->type = type;
  257. intern->msg_ce = msg_ce;
  258. #if PHP_MAJOR_VERSION < 7
  259. MAKE_STD_ZVAL(intern->array);
  260. repeated_field_array_init(intern->array, intern->type, 0 ZEND_FILE_LINE_CC);
  261. #else
  262. repeated_field_array_init(&intern->array, intern->type, 0 ZEND_FILE_LINE_CC);
  263. #endif
  264. // TODO(teboring): Link class entry for message and enum
  265. }
  266. // -----------------------------------------------------------------------------
  267. // PHP RepeatedField Methods
  268. // -----------------------------------------------------------------------------
  269. /**
  270. * Constructs an instance of RepeatedField.
  271. * @param long Type of the stored element.
  272. * @param string Message/Enum class name (message/enum fields only).
  273. */
  274. PHP_METHOD(RepeatedField, __construct) {
  275. long type;
  276. zend_class_entry* klass = NULL;
  277. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|C", &type, &klass) ==
  278. FAILURE) {
  279. return;
  280. }
  281. RepeatedField *intern = UNBOX(RepeatedField, getThis());
  282. intern->type = to_fieldtype(type);
  283. intern->msg_ce = klass;
  284. #if PHP_MAJOR_VERSION < 7
  285. MAKE_STD_ZVAL(intern->array);
  286. repeated_field_array_init(intern->array, intern->type, 0 ZEND_FILE_LINE_CC);
  287. #else
  288. repeated_field_array_init(&intern->array, intern->type, 0 ZEND_FILE_LINE_CC);
  289. #endif
  290. if (intern->type == UPB_TYPE_MESSAGE && klass == NULL) {
  291. zend_error(E_USER_ERROR, "Message type must have concrete class.");
  292. return;
  293. }
  294. // TODO(teboring): Consider enum.
  295. }
  296. /**
  297. * Append element to the end of the repeated field.
  298. * @param object The element to be added.
  299. */
  300. PHP_METHOD(RepeatedField, append) {
  301. zval *value;
  302. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) ==
  303. FAILURE) {
  304. return;
  305. }
  306. repeated_field_write_dimension(getThis(), NULL, value TSRMLS_CC);
  307. }
  308. /**
  309. * Check whether the element at given index exists.
  310. * @param long The index to be checked.
  311. * @return bool True if the element at the given index exists.
  312. */
  313. PHP_METHOD(RepeatedField, offsetExists) {
  314. long index;
  315. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) ==
  316. FAILURE) {
  317. return;
  318. }
  319. RepeatedField *intern = UNBOX(RepeatedField, getThis());
  320. RETURN_BOOL(index >= 0 &&
  321. index < zend_hash_num_elements(PHP_PROTO_HASH_OF(intern->array)));
  322. }
  323. /**
  324. * Return the element at the given index.
  325. * This will also be called for: $ele = $arr[0]
  326. * @param long The index of the element to be fetched.
  327. * @return object The stored element at given index.
  328. * @exception Invalid type for index.
  329. * @exception Non-existing index.
  330. */
  331. PHP_METHOD(RepeatedField, offsetGet) {
  332. long index;
  333. void *memory;
  334. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) ==
  335. FAILURE) {
  336. return;
  337. }
  338. RepeatedField *intern = UNBOX(RepeatedField, getThis());
  339. HashTable *table = PHP_PROTO_HASH_OF(intern->array);
  340. if (intern->type == UPB_TYPE_MESSAGE) {
  341. if (php_proto_zend_hash_index_find_zval(table, index, (void **)&memory) ==
  342. FAILURE) {
  343. zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index);
  344. return;
  345. }
  346. } else {
  347. if (php_proto_zend_hash_index_find_mem(table, index, (void **)&memory) ==
  348. FAILURE) {
  349. zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index);
  350. return;
  351. }
  352. }
  353. native_slot_get_by_array(intern->type, memory,
  354. ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
  355. }
  356. /**
  357. * Assign the element at the given index.
  358. * This will also be called for: $arr []= $ele and $arr[0] = ele
  359. * @param long The index of the element to be assigned.
  360. * @param object The element to be assigned.
  361. * @exception Invalid type for index.
  362. * @exception Non-existing index.
  363. * @exception Incorrect type of the element.
  364. */
  365. PHP_METHOD(RepeatedField, offsetSet) {
  366. zval *index, *value;
  367. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) ==
  368. FAILURE) {
  369. return;
  370. }
  371. repeated_field_write_dimension(getThis(), index, value TSRMLS_CC);
  372. }
  373. /**
  374. * Remove the element at the given index.
  375. * This will also be called for: unset($arr)
  376. * @param long The index of the element to be removed.
  377. * @exception Invalid type for index.
  378. * @exception The element to be removed is not at the end of the RepeatedField.
  379. */
  380. PHP_METHOD(RepeatedField, offsetUnset) {
  381. long index;
  382. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) ==
  383. FAILURE) {
  384. return;
  385. }
  386. RepeatedField *intern = UNBOX(RepeatedField, getThis());
  387. // Only the element at the end of the array can be removed.
  388. if (index == -1 ||
  389. index != (zend_hash_num_elements(PHP_PROTO_HASH_OF(intern->array)) - 1)) {
  390. zend_error(E_USER_ERROR, "Cannot remove element at %ld.\n", index);
  391. return;
  392. }
  393. zend_hash_index_del(PHP_PROTO_HASH_OF(intern->array), index);
  394. }
  395. /**
  396. * Return the number of stored elements.
  397. * This will also be called for: count($arr)
  398. * @return long The number of stored elements.
  399. */
  400. PHP_METHOD(RepeatedField, count) {
  401. RepeatedField *intern = UNBOX(RepeatedField, getThis());
  402. if (zend_parse_parameters_none() == FAILURE) {
  403. return;
  404. }
  405. RETURN_LONG(zend_hash_num_elements(PHP_PROTO_HASH_OF(intern->array)));
  406. }
  407. /**
  408. * Return the beginning iterator.
  409. * This will also be called for: foreach($arr)
  410. * @return object Beginning iterator.
  411. */
  412. PHP_METHOD(RepeatedField, getIterator) {
  413. CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(return_value,
  414. repeated_field_iter_type);
  415. RepeatedField *intern = UNBOX(RepeatedField, getThis());
  416. RepeatedFieldIter *iter = UNBOX(RepeatedFieldIter, return_value);
  417. iter->repeated_field = intern;
  418. iter->position = 0;
  419. }
  420. // -----------------------------------------------------------------------------
  421. // RepeatedFieldIter creation/desctruction
  422. // -----------------------------------------------------------------------------
  423. // Define object free method.
  424. PHP_PROTO_OBJECT_FREE_START(RepeatedFieldIter, repeated_field_iter)
  425. PHP_PROTO_OBJECT_FREE_END
  426. PHP_PROTO_OBJECT_DTOR_START(RepeatedFieldIter, repeated_field_iter)
  427. PHP_PROTO_OBJECT_DTOR_END
  428. // Define object create method.
  429. PHP_PROTO_OBJECT_CREATE_START(RepeatedFieldIter, repeated_field_iter)
  430. intern->repeated_field = NULL;
  431. intern->position = 0;
  432. PHP_PROTO_OBJECT_CREATE_END(RepeatedFieldIter, repeated_field_iter)
  433. // Init class entry.
  434. PHP_PROTO_INIT_CLASS_START("Google\\Protobuf\\Internal\\RepeatedFieldIter",
  435. RepeatedFieldIter, repeated_field_iter)
  436. zend_class_implements(repeated_field_iter_type TSRMLS_CC, 1, zend_ce_iterator);
  437. PHP_PROTO_INIT_CLASS_END
  438. // -----------------------------------------------------------------------------
  439. // PHP RepeatedFieldIter Methods
  440. // -----------------------------------------------------------------------------
  441. PHP_METHOD(RepeatedFieldIter, rewind) {
  442. RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis());
  443. intern->position = 0;
  444. }
  445. PHP_METHOD(RepeatedFieldIter, current) {
  446. RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis());
  447. RepeatedField *repeated_field = intern->repeated_field;
  448. long index;
  449. void *memory;
  450. HashTable *table = PHP_PROTO_HASH_OF(repeated_field->array);
  451. if (repeated_field->type == UPB_TYPE_MESSAGE) {
  452. if (php_proto_zend_hash_index_find_zval(table, intern->position,
  453. (void **)&memory) == FAILURE) {
  454. zend_error(E_USER_ERROR, "Element at %d doesn't exist.\n", index);
  455. return;
  456. }
  457. } else {
  458. if (php_proto_zend_hash_index_find_mem(table, intern->position,
  459. (void **)&memory) == FAILURE) {
  460. zend_error(E_USER_ERROR, "Element at %d doesn't exist.\n", index);
  461. return;
  462. }
  463. }
  464. native_slot_get_by_array(repeated_field->type, memory,
  465. ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
  466. }
  467. PHP_METHOD(RepeatedFieldIter, key) {
  468. RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis());
  469. RETURN_LONG(intern->position);
  470. }
  471. PHP_METHOD(RepeatedFieldIter, next) {
  472. RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis());
  473. ++intern->position;
  474. }
  475. PHP_METHOD(RepeatedFieldIter, valid) {
  476. RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis());
  477. RETURN_BOOL(zend_hash_num_elements(PHP_PROTO_HASH_OF(
  478. intern->repeated_field->array)) > intern->position);
  479. }