map.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  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 "map.h"
  31. #include <Zend/zend_API.h>
  32. #include <Zend/zend_interfaces.h>
  33. #include <ext/spl/spl_iterators.h>
  34. #include "arena.h"
  35. #include "convert.h"
  36. #include "message.h"
  37. #include "php-upb.h"
  38. #include "protobuf.h"
  39. static void MapFieldIter_make(zval *val, zval *map_field);
  40. // -----------------------------------------------------------------------------
  41. // MapField
  42. // -----------------------------------------------------------------------------
  43. typedef struct {
  44. zend_object std;
  45. zval arena;
  46. upb_map *map;
  47. MapField_Type type;
  48. } MapField;
  49. zend_class_entry *MapField_class_entry;
  50. static zend_object_handlers MapField_object_handlers;
  51. static bool MapType_Eq(MapField_Type a, MapField_Type b) {
  52. return a.key_type == b.key_type && TypeInfo_Eq(a.val_type, b.val_type);
  53. }
  54. static TypeInfo KeyType(MapField_Type type) {
  55. TypeInfo ret = {type.key_type};
  56. return ret;
  57. }
  58. MapField_Type MapType_Get(const upb_fielddef *f) {
  59. const upb_msgdef *ent = upb_fielddef_msgsubdef(f);
  60. const upb_fielddef *key_f = upb_msgdef_itof(ent, 1);
  61. const upb_fielddef *val_f = upb_msgdef_itof(ent, 2);
  62. MapField_Type type = {
  63. upb_fielddef_type(key_f),
  64. {upb_fielddef_type(val_f), Descriptor_GetFromFieldDef(val_f)}};
  65. return type;
  66. }
  67. // PHP Object Handlers /////////////////////////////////////////////////////////
  68. /**
  69. * MapField_create()
  70. *
  71. * PHP class entry function to allocate and initialize a new MapField
  72. * object.
  73. */
  74. static zend_object* MapField_create(zend_class_entry *class_type) {
  75. MapField *intern = emalloc(sizeof(MapField));
  76. zend_object_std_init(&intern->std, class_type);
  77. intern->std.handlers = &MapField_object_handlers;
  78. Arena_Init(&intern->arena);
  79. intern->map = NULL;
  80. // Skip object_properties_init(), we don't allow derived classes.
  81. return &intern->std;
  82. }
  83. /**
  84. * MapField_dtor()
  85. *
  86. * Object handler to destroy a MapField. This releases all resources
  87. * associated with the message. Note that it is possible to access a destroyed
  88. * object from PHP in rare cases.
  89. */
  90. static void MapField_destructor(zend_object* obj) {
  91. MapField* intern = (MapField*)obj;
  92. ObjCache_Delete(intern->map);
  93. zval_ptr_dtor(&intern->arena);
  94. zend_object_std_dtor(&intern->std);
  95. }
  96. /**
  97. * MapField_compare_objects()
  98. *
  99. * Object handler for comparing two repeated field objects. Called whenever PHP
  100. * code does:
  101. *
  102. * $map1 == $map2
  103. */
  104. static int MapField_compare_objects(zval *map1, zval *map2) {
  105. MapField* intern1 = (MapField*)Z_OBJ_P(map1);
  106. MapField* intern2 = (MapField*)Z_OBJ_P(map2);
  107. return MapType_Eq(intern1->type, intern2->type) &&
  108. MapEq(intern1->map, intern2->map, intern1->type)
  109. ? 0
  110. : 1;
  111. }
  112. /**
  113. * MapField_clone_obj()
  114. *
  115. * Object handler for cloning an object in PHP. Called when PHP code does:
  116. *
  117. * $map2 = clone $map1;
  118. */
  119. static zend_object *MapField_clone_obj(zval *object) {
  120. MapField* intern = (MapField*)Z_OBJ_P(object);
  121. upb_arena *arena = Arena_Get(&intern->arena);
  122. upb_map *clone =
  123. upb_map_new(arena, intern->type.key_type, intern->type.val_type.type);
  124. size_t iter = UPB_MAP_BEGIN;
  125. while (upb_mapiter_next(intern->map, &iter)) {
  126. upb_msgval key = upb_mapiter_key(intern->map, iter);
  127. upb_msgval val = upb_mapiter_value(intern->map, iter);
  128. upb_map_set(clone, key, val, arena);
  129. }
  130. zval ret;
  131. MapField_GetPhpWrapper(&ret, clone, intern->type, &intern->arena);
  132. return Z_OBJ_P(&ret);
  133. }
  134. static zval *Map_GetPropertyPtrPtr(PROTO_VAL *object, PROTO_STR *member,
  135. int type, void **cache_slot) {
  136. return NULL; // We don't offer direct references to our properties.
  137. }
  138. static HashTable *Map_GetProperties(PROTO_VAL *object) {
  139. return NULL; // We do not have a properties table.
  140. }
  141. // C Functions from map.h //////////////////////////////////////////////////////
  142. // These are documented in the header file.
  143. void MapField_GetPhpWrapper(zval *val, upb_map *map, MapField_Type type,
  144. zval *arena) {
  145. if (!map) {
  146. ZVAL_NULL(val);
  147. return;
  148. }
  149. if (!ObjCache_Get(map, val)) {
  150. MapField *intern = emalloc(sizeof(MapField));
  151. zend_object_std_init(&intern->std, MapField_class_entry);
  152. intern->std.handlers = &MapField_object_handlers;
  153. ZVAL_COPY(&intern->arena, arena);
  154. intern->map = map;
  155. intern->type = type;
  156. // Skip object_properties_init(), we don't allow derived classes.
  157. ObjCache_Add(intern->map, &intern->std);
  158. ZVAL_OBJ(val, &intern->std);
  159. }
  160. }
  161. upb_map *MapField_GetUpbMap(zval *val, MapField_Type type, upb_arena *arena) {
  162. if (Z_ISREF_P(val)) {
  163. ZVAL_DEREF(val);
  164. }
  165. if (Z_TYPE_P(val) == IS_ARRAY) {
  166. upb_map *map = upb_map_new(arena, type.key_type, type.val_type.type);
  167. HashTable *table = HASH_OF(val);
  168. HashPosition pos;
  169. zend_hash_internal_pointer_reset_ex(table, &pos);
  170. while (true) {
  171. zval php_key;
  172. zval *php_val;
  173. upb_msgval upb_key;
  174. upb_msgval upb_val;
  175. zend_hash_get_current_key_zval_ex(table, &php_key, &pos);
  176. php_val = zend_hash_get_current_data_ex(table, &pos);
  177. if (!php_val) return map;
  178. if (!Convert_PhpToUpb(&php_key, &upb_key, KeyType(type), arena) ||
  179. !Convert_PhpToUpbAutoWrap(php_val, &upb_val, type.val_type, arena)) {
  180. return NULL;
  181. }
  182. upb_map_set(map, upb_key, upb_val, arena);
  183. zend_hash_move_forward_ex(table, &pos);
  184. zval_dtor(&php_key);
  185. }
  186. } else if (Z_TYPE_P(val) == IS_OBJECT &&
  187. Z_OBJCE_P(val) == MapField_class_entry) {
  188. MapField *intern = (MapField*)Z_OBJ_P(val);
  189. if (!MapType_Eq(intern->type, type)) {
  190. php_error_docref(NULL, E_USER_ERROR, "Wrong type for this map field.");
  191. return NULL;
  192. }
  193. upb_arena_fuse(arena, Arena_Get(&intern->arena));
  194. return intern->map;
  195. } else {
  196. php_error_docref(NULL, E_USER_ERROR, "Must be a map");
  197. return NULL;
  198. }
  199. }
  200. bool MapEq(const upb_map *m1, const upb_map *m2, MapField_Type type) {
  201. size_t iter = UPB_MAP_BEGIN;
  202. if ((m1 == NULL) != (m2 == NULL)) return false;
  203. if (m1 == NULL) return true;
  204. if (upb_map_size(m1) != upb_map_size(m2)) return false;
  205. while (upb_mapiter_next(m1, &iter)) {
  206. upb_msgval key = upb_mapiter_key(m1, iter);
  207. upb_msgval val1 = upb_mapiter_value(m1, iter);
  208. upb_msgval val2;
  209. if (!upb_map_get(m2, key, &val2)) return false;
  210. if (!ValueEq(val1, val2, type.val_type)) return false;
  211. }
  212. return true;
  213. }
  214. // MapField PHP methods ////////////////////////////////////////////////////////
  215. /**
  216. * MapField::__construct()
  217. *
  218. * Constructs an instance of MapField.
  219. * @param long Key type.
  220. * @param long Value type.
  221. * @param string Message/Enum class (message/enum value types only).
  222. */
  223. PHP_METHOD(MapField, __construct) {
  224. MapField *intern = (MapField*)Z_OBJ_P(getThis());
  225. upb_arena *arena = Arena_Get(&intern->arena);
  226. zend_long key_type, val_type;
  227. zend_class_entry* klass = NULL;
  228. if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll|C", &key_type, &val_type,
  229. &klass) != SUCCESS) {
  230. return;
  231. }
  232. intern->type.key_type = pbphp_dtype_to_type(key_type);
  233. intern->type.val_type.type = pbphp_dtype_to_type(val_type);
  234. intern->type.val_type.desc = Descriptor_GetFromClassEntry(klass);
  235. // Check that the key type is an allowed type.
  236. switch (intern->type.key_type) {
  237. case UPB_TYPE_INT32:
  238. case UPB_TYPE_INT64:
  239. case UPB_TYPE_UINT32:
  240. case UPB_TYPE_UINT64:
  241. case UPB_TYPE_BOOL:
  242. case UPB_TYPE_STRING:
  243. case UPB_TYPE_BYTES:
  244. // These are OK.
  245. break;
  246. default:
  247. zend_error(E_USER_ERROR, "Invalid key type for map.");
  248. }
  249. if (intern->type.val_type.type == UPB_TYPE_MESSAGE && klass == NULL) {
  250. php_error_docref(NULL, E_USER_ERROR,
  251. "Message/enum type must have concrete class.");
  252. return;
  253. }
  254. intern->map =
  255. upb_map_new(arena, intern->type.key_type, intern->type.val_type.type);
  256. ObjCache_Add(intern->map, &intern->std);
  257. }
  258. /**
  259. * MapField::offsetExists()
  260. *
  261. * Implements the ArrayAccess interface. Invoked when PHP code calls:
  262. *
  263. * isset($map[$idx]);
  264. * empty($map[$idx]);
  265. *
  266. * @param long The index to be checked.
  267. * @return bool True if the element at the given index exists.
  268. */
  269. PHP_METHOD(MapField, offsetExists) {
  270. MapField *intern = (MapField*)Z_OBJ_P(getThis());
  271. zval *key;
  272. upb_msgval upb_key;
  273. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &key) != SUCCESS ||
  274. !Convert_PhpToUpb(key, &upb_key, KeyType(intern->type), NULL)) {
  275. return;
  276. }
  277. RETURN_BOOL(upb_map_get(intern->map, upb_key, NULL));
  278. }
  279. /**
  280. * MapField::offsetGet()
  281. *
  282. * Implements the ArrayAccess interface. Invoked when PHP code calls:
  283. *
  284. * $x = $map[$idx];
  285. *
  286. * @param long The index of the element to be fetched.
  287. * @return object The stored element at given index.
  288. * @exception Invalid type for index.
  289. * @exception Non-existing index.
  290. */
  291. PHP_METHOD(MapField, offsetGet) {
  292. MapField *intern = (MapField*)Z_OBJ_P(getThis());
  293. zval *key;
  294. zval ret;
  295. upb_msgval upb_key, upb_val;
  296. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &key) != SUCCESS ||
  297. !Convert_PhpToUpb(key, &upb_key, KeyType(intern->type), NULL)) {
  298. return;
  299. }
  300. if (!upb_map_get(intern->map, upb_key, &upb_val)) {
  301. zend_error(E_USER_ERROR, "Given key doesn't exist.");
  302. return;
  303. }
  304. Convert_UpbToPhp(upb_val, &ret, intern->type.val_type, &intern->arena);
  305. RETURN_ZVAL(&ret, 0, 1);
  306. }
  307. /**
  308. * MapField::offsetSet()
  309. *
  310. * Implements the ArrayAccess interface. Invoked when PHP code calls:
  311. *
  312. * $map[$idx] = $x;
  313. *
  314. * @param long The index of the element to be assigned.
  315. * @param object The element to be assigned.
  316. * @exception Invalid type for index.
  317. * @exception Non-existing index.
  318. * @exception Incorrect type of the element.
  319. */
  320. PHP_METHOD(MapField, offsetSet) {
  321. MapField *intern = (MapField*)Z_OBJ_P(getThis());
  322. upb_arena *arena = Arena_Get(&intern->arena);
  323. zval *key, *val;
  324. upb_msgval upb_key, upb_val;
  325. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &key, &val) != SUCCESS ||
  326. !Convert_PhpToUpb(key, &upb_key, KeyType(intern->type), NULL) ||
  327. !Convert_PhpToUpb(val, &upb_val, intern->type.val_type, arena)) {
  328. return;
  329. }
  330. upb_map_set(intern->map, upb_key, upb_val, arena);
  331. }
  332. /**
  333. * MapField::offsetUnset()
  334. *
  335. * Implements the ArrayAccess interface. Invoked when PHP code calls:
  336. *
  337. * unset($map[$idx]);
  338. *
  339. * @param long The index of the element to be removed.
  340. * @exception Invalid type for index.
  341. * @exception The element to be removed is not at the end of the MapField.
  342. */
  343. PHP_METHOD(MapField, offsetUnset) {
  344. MapField *intern = (MapField*)Z_OBJ_P(getThis());
  345. zval *key;
  346. upb_msgval upb_key;
  347. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &key) != SUCCESS ||
  348. !Convert_PhpToUpb(key, &upb_key, KeyType(intern->type), NULL)) {
  349. return;
  350. }
  351. upb_map_delete(intern->map, upb_key);
  352. }
  353. /**
  354. * MapField::count()
  355. *
  356. * Implements the Countable interface. Invoked when PHP code calls:
  357. *
  358. * $len = count($map);
  359. * Return the number of stored elements.
  360. * This will also be called for: count($map)
  361. * @return long The number of stored elements.
  362. */
  363. PHP_METHOD(MapField, count) {
  364. MapField *intern = (MapField*)Z_OBJ_P(getThis());
  365. if (zend_parse_parameters_none() == FAILURE) {
  366. return;
  367. }
  368. RETURN_LONG(upb_map_size(intern->map));
  369. }
  370. /**
  371. * MapField::getIterator()
  372. *
  373. * Implements the IteratorAggregate interface. Invoked when PHP code calls:
  374. *
  375. * foreach ($arr) {}
  376. *
  377. * @return object Beginning iterator.
  378. */
  379. PHP_METHOD(MapField, getIterator) {
  380. zval ret;
  381. MapFieldIter_make(&ret, getThis());
  382. RETURN_ZVAL(&ret, 0, 1);
  383. }
  384. ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 2)
  385. ZEND_ARG_INFO(0, key_type)
  386. ZEND_ARG_INFO(0, value_type)
  387. ZEND_ARG_INFO(0, value_class)
  388. ZEND_END_ARG_INFO()
  389. ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1)
  390. ZEND_ARG_INFO(0, index)
  391. ZEND_END_ARG_INFO()
  392. ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2)
  393. ZEND_ARG_INFO(0, index)
  394. ZEND_ARG_INFO(0, newval)
  395. ZEND_END_ARG_INFO()
  396. static zend_function_entry MapField_methods[] = {
  397. PHP_ME(MapField, __construct, arginfo_construct, ZEND_ACC_PUBLIC)
  398. PHP_ME(MapField, offsetExists, arginfo_offsetGet, ZEND_ACC_PUBLIC)
  399. PHP_ME(MapField, offsetGet, arginfo_offsetGet, ZEND_ACC_PUBLIC)
  400. PHP_ME(MapField, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC)
  401. PHP_ME(MapField, offsetUnset, arginfo_offsetGet, ZEND_ACC_PUBLIC)
  402. PHP_ME(MapField, count, arginfo_void, ZEND_ACC_PUBLIC)
  403. PHP_ME(MapField, getIterator, arginfo_void, ZEND_ACC_PUBLIC)
  404. ZEND_FE_END
  405. };
  406. // -----------------------------------------------------------------------------
  407. // MapFieldIter
  408. // -----------------------------------------------------------------------------
  409. typedef struct {
  410. zend_object std;
  411. zval map_field;
  412. size_t position;
  413. } MapFieldIter;
  414. zend_class_entry *MapFieldIter_class_entry;
  415. static zend_object_handlers MapFieldIter_object_handlers;
  416. /**
  417. * MapFieldIter_create()
  418. *
  419. * PHP class entry function to allocate and initialize a new MapFieldIter
  420. * object.
  421. */
  422. zend_object* MapFieldIter_create(zend_class_entry *class_type) {
  423. MapFieldIter *intern = emalloc(sizeof(MapFieldIter));
  424. zend_object_std_init(&intern->std, class_type);
  425. intern->std.handlers = &MapFieldIter_object_handlers;
  426. ZVAL_NULL(&intern->map_field);
  427. intern->position = 0;
  428. // Skip object_properties_init(), we don't allow derived classes.
  429. return &intern->std;
  430. }
  431. /**
  432. * MapFieldIter_dtor()
  433. *
  434. * Object handler to destroy a MapFieldIter. This releases all resources
  435. * associated with the message. Note that it is possible to access a destroyed
  436. * object from PHP in rare cases.
  437. */
  438. static void map_field_iter_dtor(zend_object* obj) {
  439. MapFieldIter* intern = (MapFieldIter*)obj;
  440. zval_ptr_dtor(&intern->map_field);
  441. zend_object_std_dtor(&intern->std);
  442. }
  443. /**
  444. * MapFieldIter_make()
  445. *
  446. * Function to create a MapFieldIter directly from C.
  447. */
  448. static void MapFieldIter_make(zval *val, zval *map_field) {
  449. MapFieldIter *iter;
  450. ZVAL_OBJ(val,
  451. MapFieldIter_class_entry->create_object(MapFieldIter_class_entry));
  452. iter = (MapFieldIter*)Z_OBJ_P(val);
  453. ZVAL_COPY(&iter->map_field, map_field);
  454. }
  455. // -----------------------------------------------------------------------------
  456. // PHP MapFieldIter Methods
  457. // -----------------------------------------------------------------------------
  458. /*
  459. * When a user writes:
  460. *
  461. * foreach($arr as $key => $val) {}
  462. *
  463. * PHP translates this into:
  464. *
  465. * $iter = $arr->getIterator();
  466. * for ($iter->rewind(); $iter->valid(); $iter->next()) {
  467. * $key = $iter->key();
  468. * $val = $iter->current();
  469. * }
  470. */
  471. /**
  472. * MapFieldIter::rewind()
  473. *
  474. * Implements the Iterator interface. Sets the iterator to the first element.
  475. */
  476. PHP_METHOD(MapFieldIter, rewind) {
  477. MapFieldIter *intern = (MapFieldIter*)Z_OBJ_P(getThis());
  478. MapField *map_field = (MapField*)Z_OBJ_P(&intern->map_field);
  479. intern->position = UPB_MAP_BEGIN;
  480. upb_mapiter_next(map_field->map, &intern->position);
  481. }
  482. /**
  483. * MapFieldIter::current()
  484. *
  485. * Implements the Iterator interface. Returns the current value.
  486. */
  487. PHP_METHOD(MapFieldIter, current) {
  488. MapFieldIter *intern = (MapFieldIter*)Z_OBJ_P(getThis());
  489. MapField *field = (MapField*)Z_OBJ_P(&intern->map_field);
  490. upb_msgval upb_val = upb_mapiter_value(field->map, intern->position);
  491. zval ret;
  492. Convert_UpbToPhp(upb_val, &ret, field->type.val_type, &field->arena);
  493. RETURN_ZVAL(&ret, 0, 1);
  494. }
  495. /**
  496. * MapFieldIter::key()
  497. *
  498. * Implements the Iterator interface. Returns the current key.
  499. */
  500. PHP_METHOD(MapFieldIter, key) {
  501. MapFieldIter *intern = (MapFieldIter*)Z_OBJ_P(getThis());
  502. MapField *field = (MapField*)Z_OBJ_P(&intern->map_field);
  503. upb_msgval upb_key = upb_mapiter_key(field->map, intern->position);
  504. zval ret;
  505. Convert_UpbToPhp(upb_key, &ret, KeyType(field->type), NULL);
  506. RETURN_ZVAL(&ret, 0, 1);
  507. }
  508. /**
  509. * MapFieldIter::next()
  510. *
  511. * Implements the Iterator interface. Advances to the next element.
  512. */
  513. PHP_METHOD(MapFieldIter, next) {
  514. MapFieldIter *intern = (MapFieldIter*)Z_OBJ_P(getThis());
  515. MapField *field = (MapField*)Z_OBJ_P(&intern->map_field);
  516. upb_mapiter_next(field->map, &intern->position);
  517. }
  518. /**
  519. * MapFieldIter::valid()
  520. *
  521. * Implements the Iterator interface. Returns true if this is a valid element.
  522. */
  523. PHP_METHOD(MapFieldIter, valid) {
  524. MapFieldIter *intern = (MapFieldIter*)Z_OBJ_P(getThis());
  525. MapField *field = (MapField*)Z_OBJ_P(&intern->map_field);
  526. bool done = upb_mapiter_done(field->map, intern->position);
  527. RETURN_BOOL(!done);
  528. }
  529. static zend_function_entry map_field_iter_methods[] = {
  530. PHP_ME(MapFieldIter, rewind, arginfo_void, ZEND_ACC_PUBLIC)
  531. PHP_ME(MapFieldIter, current, arginfo_void, ZEND_ACC_PUBLIC)
  532. PHP_ME(MapFieldIter, key, arginfo_void, ZEND_ACC_PUBLIC)
  533. PHP_ME(MapFieldIter, next, arginfo_void, ZEND_ACC_PUBLIC)
  534. PHP_ME(MapFieldIter, valid, arginfo_void, ZEND_ACC_PUBLIC)
  535. ZEND_FE_END
  536. };
  537. // -----------------------------------------------------------------------------
  538. // Module init.
  539. // -----------------------------------------------------------------------------
  540. /**
  541. * Map_ModuleInit()
  542. *
  543. * Called when the C extension is loaded to register all types.
  544. */
  545. void Map_ModuleInit() {
  546. zend_class_entry tmp_ce;
  547. zend_object_handlers *h;
  548. INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\MapField",
  549. MapField_methods);
  550. MapField_class_entry = zend_register_internal_class(&tmp_ce);
  551. zend_class_implements(MapField_class_entry, 3, spl_ce_ArrayAccess,
  552. zend_ce_aggregate, spl_ce_Countable);
  553. MapField_class_entry->ce_flags |= ZEND_ACC_FINAL;
  554. MapField_class_entry->create_object = MapField_create;
  555. h = &MapField_object_handlers;
  556. memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
  557. h->dtor_obj = MapField_destructor;
  558. #if PHP_VERSION_ID < 80000
  559. h->compare_objects = MapField_compare_objects;
  560. #else
  561. h->compare = MapField_compare_objects;
  562. #endif
  563. h->clone_obj = MapField_clone_obj;
  564. h->get_properties = Map_GetProperties;
  565. h->get_property_ptr_ptr = Map_GetPropertyPtrPtr;
  566. INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\MapFieldIter",
  567. map_field_iter_methods);
  568. MapFieldIter_class_entry = zend_register_internal_class(&tmp_ce);
  569. zend_class_implements(MapFieldIter_class_entry, 1, zend_ce_iterator);
  570. MapFieldIter_class_entry->ce_flags |= ZEND_ACC_FINAL;
  571. MapFieldIter_class_entry->ce_flags |= ZEND_ACC_FINAL;
  572. MapFieldIter_class_entry->create_object = MapFieldIter_create;
  573. h = &MapFieldIter_object_handlers;
  574. memcpy(h, &std_object_handlers, sizeof(zend_object_handlers));
  575. h->dtor_obj = map_field_iter_dtor;
  576. }