spl_dllist.c 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Etienne Kneuss <colder@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifdef HAVE_CONFIG_H
  17. # include "config.h"
  18. #endif
  19. #include "php.h"
  20. #include "zend_exceptions.h"
  21. #include "zend_hash.h"
  22. #include "php_spl.h"
  23. #include "ext/standard/info.h"
  24. #include "ext/standard/php_var.h"
  25. #include "zend_smart_str.h"
  26. #include "spl_functions.h"
  27. #include "spl_engine.h"
  28. #include "spl_iterators.h"
  29. #include "spl_dllist.h"
  30. #include "spl_dllist_arginfo.h"
  31. #include "spl_exceptions.h"
  32. zend_object_handlers spl_handler_SplDoublyLinkedList;
  33. PHPAPI zend_class_entry *spl_ce_SplDoublyLinkedList;
  34. PHPAPI zend_class_entry *spl_ce_SplQueue;
  35. PHPAPI zend_class_entry *spl_ce_SplStack;
  36. #define SPL_LLIST_RC(elem) Z_EXTRA((elem)->data)
  37. #define SPL_LLIST_DELREF(elem) if (!--SPL_LLIST_RC(elem)) { \
  38. efree(elem); \
  39. }
  40. #define SPL_LLIST_CHECK_DELREF(elem) if ((elem) && !--SPL_LLIST_RC(elem)) { \
  41. efree(elem); \
  42. }
  43. #define SPL_LLIST_ADDREF(elem) SPL_LLIST_RC(elem)++
  44. #define SPL_LLIST_CHECK_ADDREF(elem) if (elem) SPL_LLIST_RC(elem)++
  45. #define SPL_DLLIST_IT_DELETE 0x00000001 /* Delete flag makes the iterator delete the current element on next */
  46. #define SPL_DLLIST_IT_LIFO 0x00000002 /* LIFO flag makes the iterator traverse the structure as a LastInFirstOut */
  47. #define SPL_DLLIST_IT_MASK 0x00000003 /* Mask to isolate flags related to iterators */
  48. #define SPL_DLLIST_IT_FIX 0x00000004 /* Backward/Forward bit is fixed */
  49. #ifdef accept
  50. #undef accept
  51. #endif
  52. typedef struct _spl_ptr_llist_element {
  53. struct _spl_ptr_llist_element *prev;
  54. struct _spl_ptr_llist_element *next;
  55. zval data;
  56. } spl_ptr_llist_element;
  57. typedef struct _spl_ptr_llist {
  58. spl_ptr_llist_element *head;
  59. spl_ptr_llist_element *tail;
  60. int count;
  61. } spl_ptr_llist;
  62. typedef struct _spl_dllist_object spl_dllist_object;
  63. typedef struct _spl_dllist_it spl_dllist_it;
  64. struct _spl_dllist_object {
  65. spl_ptr_llist *llist;
  66. int traverse_position;
  67. spl_ptr_llist_element *traverse_pointer;
  68. int flags;
  69. zend_function *fptr_offset_get;
  70. zend_function *fptr_offset_set;
  71. zend_function *fptr_offset_has;
  72. zend_function *fptr_offset_del;
  73. zend_function *fptr_count;
  74. zend_class_entry *ce_get_iterator;
  75. zend_object std;
  76. };
  77. /* define an overloaded iterator structure */
  78. struct _spl_dllist_it {
  79. zend_user_iterator intern;
  80. spl_ptr_llist_element *traverse_pointer;
  81. int traverse_position;
  82. int flags;
  83. };
  84. static inline spl_dllist_object *spl_dllist_from_obj(zend_object *obj) /* {{{ */ {
  85. return (spl_dllist_object*)((char*)(obj) - XtOffsetOf(spl_dllist_object, std));
  86. }
  87. /* }}} */
  88. #define Z_SPLDLLIST_P(zv) spl_dllist_from_obj(Z_OBJ_P((zv)))
  89. static spl_ptr_llist *spl_ptr_llist_init(void) /* {{{ */
  90. {
  91. spl_ptr_llist *llist = emalloc(sizeof(spl_ptr_llist));
  92. llist->head = NULL;
  93. llist->tail = NULL;
  94. llist->count = 0;
  95. return llist;
  96. }
  97. /* }}} */
  98. static zend_long spl_ptr_llist_count(spl_ptr_llist *llist) /* {{{ */
  99. {
  100. return (zend_long)llist->count;
  101. }
  102. /* }}} */
  103. static void spl_ptr_llist_destroy(spl_ptr_llist *llist) /* {{{ */
  104. {
  105. spl_ptr_llist_element *current = llist->head, *next;
  106. while (current) {
  107. next = current->next;
  108. zval_ptr_dtor(&current->data);
  109. SPL_LLIST_DELREF(current);
  110. current = next;
  111. }
  112. efree(llist);
  113. }
  114. /* }}} */
  115. static spl_ptr_llist_element *spl_ptr_llist_offset(spl_ptr_llist *llist, zend_long offset, int backward) /* {{{ */
  116. {
  117. spl_ptr_llist_element *current;
  118. int pos = 0;
  119. if (backward) {
  120. current = llist->tail;
  121. } else {
  122. current = llist->head;
  123. }
  124. while (current && pos < offset) {
  125. pos++;
  126. if (backward) {
  127. current = current->prev;
  128. } else {
  129. current = current->next;
  130. }
  131. }
  132. return current;
  133. }
  134. /* }}} */
  135. static void spl_ptr_llist_unshift(spl_ptr_llist *llist, zval *data) /* {{{ */
  136. {
  137. spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element));
  138. elem->prev = NULL;
  139. elem->next = llist->head;
  140. ZVAL_COPY(&elem->data, data);
  141. SPL_LLIST_RC(elem) = 1;
  142. if (llist->head) {
  143. llist->head->prev = elem;
  144. } else {
  145. llist->tail = elem;
  146. }
  147. llist->head = elem;
  148. llist->count++;
  149. }
  150. /* }}} */
  151. static void spl_ptr_llist_push(spl_ptr_llist *llist, zval *data) /* {{{ */
  152. {
  153. spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element));
  154. elem->prev = llist->tail;
  155. elem->next = NULL;
  156. ZVAL_COPY(&elem->data, data);
  157. SPL_LLIST_RC(elem) = 1;
  158. if (llist->tail) {
  159. llist->tail->next = elem;
  160. } else {
  161. llist->head = elem;
  162. }
  163. llist->tail = elem;
  164. llist->count++;
  165. }
  166. /* }}} */
  167. static void spl_ptr_llist_pop(spl_ptr_llist *llist, zval *ret) /* {{{ */
  168. {
  169. spl_ptr_llist_element *tail = llist->tail;
  170. if (tail == NULL) {
  171. ZVAL_UNDEF(ret);
  172. return;
  173. }
  174. if (tail->prev) {
  175. tail->prev->next = NULL;
  176. } else {
  177. llist->head = NULL;
  178. }
  179. llist->tail = tail->prev;
  180. llist->count--;
  181. ZVAL_COPY_VALUE(ret, &tail->data);
  182. ZVAL_UNDEF(&tail->data);
  183. tail->prev = NULL;
  184. SPL_LLIST_DELREF(tail);
  185. }
  186. /* }}} */
  187. static zval *spl_ptr_llist_last(spl_ptr_llist *llist) /* {{{ */
  188. {
  189. spl_ptr_llist_element *tail = llist->tail;
  190. if (tail == NULL) {
  191. return NULL;
  192. } else {
  193. return &tail->data;
  194. }
  195. }
  196. /* }}} */
  197. static zval *spl_ptr_llist_first(spl_ptr_llist *llist) /* {{{ */
  198. {
  199. spl_ptr_llist_element *head = llist->head;
  200. if (head == NULL) {
  201. return NULL;
  202. } else {
  203. return &head->data;
  204. }
  205. }
  206. /* }}} */
  207. static void spl_ptr_llist_shift(spl_ptr_llist *llist, zval *ret) /* {{{ */
  208. {
  209. spl_ptr_llist_element *head = llist->head;
  210. if (head == NULL) {
  211. ZVAL_UNDEF(ret);
  212. return;
  213. }
  214. if (head->next) {
  215. head->next->prev = NULL;
  216. } else {
  217. llist->tail = NULL;
  218. }
  219. llist->head = head->next;
  220. llist->count--;
  221. ZVAL_COPY_VALUE(ret, &head->data);
  222. ZVAL_UNDEF(&head->data);
  223. head->next = NULL;
  224. SPL_LLIST_DELREF(head);
  225. }
  226. /* }}} */
  227. static void spl_ptr_llist_copy(spl_ptr_llist *from, spl_ptr_llist *to) /* {{{ */
  228. {
  229. spl_ptr_llist_element *current = from->head, *next;
  230. while (current) {
  231. next = current->next;
  232. spl_ptr_llist_push(to, &current->data);
  233. current = next;
  234. }
  235. }
  236. /* }}} */
  237. /* }}} */
  238. static void spl_dllist_object_free_storage(zend_object *object) /* {{{ */
  239. {
  240. spl_dllist_object *intern = spl_dllist_from_obj(object);
  241. zval tmp;
  242. zend_object_std_dtor(&intern->std);
  243. while (intern->llist->count > 0) {
  244. spl_ptr_llist_pop(intern->llist, &tmp);
  245. zval_ptr_dtor(&tmp);
  246. }
  247. spl_ptr_llist_destroy(intern->llist);
  248. SPL_LLIST_CHECK_DELREF(intern->traverse_pointer);
  249. }
  250. /* }}} */
  251. static zend_object *spl_dllist_object_new_ex(zend_class_entry *class_type, zend_object *orig, int clone_orig) /* {{{ */
  252. {
  253. spl_dllist_object *intern;
  254. zend_class_entry *parent = class_type;
  255. int inherited = 0;
  256. intern = zend_object_alloc(sizeof(spl_dllist_object), parent);
  257. zend_object_std_init(&intern->std, class_type);
  258. object_properties_init(&intern->std, class_type);
  259. intern->flags = 0;
  260. intern->traverse_position = 0;
  261. if (orig) {
  262. spl_dllist_object *other = spl_dllist_from_obj(orig);
  263. intern->ce_get_iterator = other->ce_get_iterator;
  264. if (clone_orig) {
  265. intern->llist = spl_ptr_llist_init();
  266. spl_ptr_llist_copy(other->llist, intern->llist);
  267. intern->traverse_pointer = intern->llist->head;
  268. SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer);
  269. } else {
  270. intern->llist = other->llist;
  271. intern->traverse_pointer = intern->llist->head;
  272. SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer);
  273. }
  274. intern->flags = other->flags;
  275. } else {
  276. intern->llist = spl_ptr_llist_init();
  277. intern->traverse_pointer = intern->llist->head;
  278. SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer);
  279. }
  280. while (parent) {
  281. if (parent == spl_ce_SplStack) {
  282. intern->flags |= (SPL_DLLIST_IT_FIX | SPL_DLLIST_IT_LIFO);
  283. intern->std.handlers = &spl_handler_SplDoublyLinkedList;
  284. } else if (parent == spl_ce_SplQueue) {
  285. intern->flags |= SPL_DLLIST_IT_FIX;
  286. intern->std.handlers = &spl_handler_SplDoublyLinkedList;
  287. }
  288. if (parent == spl_ce_SplDoublyLinkedList) {
  289. intern->std.handlers = &spl_handler_SplDoublyLinkedList;
  290. break;
  291. }
  292. parent = parent->parent;
  293. inherited = 1;
  294. }
  295. ZEND_ASSERT(parent);
  296. if (inherited) {
  297. intern->fptr_offset_get = zend_hash_str_find_ptr(&class_type->function_table, "offsetget", sizeof("offsetget") - 1);
  298. if (intern->fptr_offset_get->common.scope == parent) {
  299. intern->fptr_offset_get = NULL;
  300. }
  301. intern->fptr_offset_set = zend_hash_str_find_ptr(&class_type->function_table, "offsetset", sizeof("offsetset") - 1);
  302. if (intern->fptr_offset_set->common.scope == parent) {
  303. intern->fptr_offset_set = NULL;
  304. }
  305. intern->fptr_offset_has = zend_hash_str_find_ptr(&class_type->function_table, "offsetexists", sizeof("offsetexists") - 1);
  306. if (intern->fptr_offset_has->common.scope == parent) {
  307. intern->fptr_offset_has = NULL;
  308. }
  309. intern->fptr_offset_del = zend_hash_str_find_ptr(&class_type->function_table, "offsetunset", sizeof("offsetunset") - 1);
  310. if (intern->fptr_offset_del->common.scope == parent) {
  311. intern->fptr_offset_del = NULL;
  312. }
  313. intern->fptr_count = zend_hash_str_find_ptr(&class_type->function_table, "count", sizeof("count") - 1);
  314. if (intern->fptr_count->common.scope == parent) {
  315. intern->fptr_count = NULL;
  316. }
  317. }
  318. return &intern->std;
  319. }
  320. /* }}} */
  321. static zend_object *spl_dllist_object_new(zend_class_entry *class_type) /* {{{ */
  322. {
  323. return spl_dllist_object_new_ex(class_type, NULL, 0);
  324. }
  325. /* }}} */
  326. static zend_object *spl_dllist_object_clone(zend_object *old_object) /* {{{ */
  327. {
  328. zend_object *new_object = spl_dllist_object_new_ex(old_object->ce, old_object, 1);
  329. zend_objects_clone_members(new_object, old_object);
  330. return new_object;
  331. }
  332. /* }}} */
  333. static int spl_dllist_object_count_elements(zend_object *object, zend_long *count) /* {{{ */
  334. {
  335. spl_dllist_object *intern = spl_dllist_from_obj(object);
  336. if (intern->fptr_count) {
  337. zval rv;
  338. zend_call_method_with_0_params(object, intern->std.ce, &intern->fptr_count, "count", &rv);
  339. if (!Z_ISUNDEF(rv)) {
  340. *count = zval_get_long(&rv);
  341. zval_ptr_dtor(&rv);
  342. return SUCCESS;
  343. }
  344. *count = 0;
  345. return FAILURE;
  346. }
  347. *count = spl_ptr_llist_count(intern->llist);
  348. return SUCCESS;
  349. }
  350. /* }}} */
  351. static inline HashTable* spl_dllist_object_get_debug_info(zend_object *obj) /* {{{{ */
  352. {
  353. spl_dllist_object *intern = spl_dllist_from_obj(obj);
  354. spl_ptr_llist_element *current = intern->llist->head, *next;
  355. zval tmp, dllist_array;
  356. zend_string *pnstr;
  357. int i = 0;
  358. HashTable *debug_info;
  359. if (!intern->std.properties) {
  360. rebuild_object_properties(&intern->std);
  361. }
  362. debug_info = zend_new_array(1);
  363. zend_hash_copy(debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref);
  364. pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "flags", sizeof("flags")-1);
  365. ZVAL_LONG(&tmp, intern->flags);
  366. zend_hash_add(debug_info, pnstr, &tmp);
  367. zend_string_release_ex(pnstr, 0);
  368. array_init(&dllist_array);
  369. while (current) {
  370. next = current->next;
  371. add_index_zval(&dllist_array, i, &current->data);
  372. if (Z_REFCOUNTED(current->data)) {
  373. Z_ADDREF(current->data);
  374. }
  375. i++;
  376. current = next;
  377. }
  378. pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "dllist", sizeof("dllist")-1);
  379. zend_hash_add(debug_info, pnstr, &dllist_array);
  380. zend_string_release_ex(pnstr, 0);
  381. return debug_info;
  382. }
  383. /* }}}} */
  384. static HashTable *spl_dllist_object_get_gc(zend_object *obj, zval **gc_data, int *gc_data_count) /* {{{ */
  385. {
  386. spl_dllist_object *intern = spl_dllist_from_obj(obj);
  387. zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create();
  388. spl_ptr_llist_element *current = intern->llist->head;
  389. while (current) {
  390. zend_get_gc_buffer_add_zval(gc_buffer, &current->data);
  391. current = current->next;
  392. }
  393. zend_get_gc_buffer_use(gc_buffer, gc_data, gc_data_count);
  394. return zend_std_get_properties(obj);
  395. }
  396. /* }}} */
  397. /* {{{ Push $value on the SplDoublyLinkedList */
  398. PHP_METHOD(SplDoublyLinkedList, push)
  399. {
  400. zval *value;
  401. spl_dllist_object *intern;
  402. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &value) == FAILURE) {
  403. RETURN_THROWS();
  404. }
  405. intern = Z_SPLDLLIST_P(ZEND_THIS);
  406. spl_ptr_llist_push(intern->llist, value);
  407. }
  408. /* }}} */
  409. /* {{{ Unshift $value on the SplDoublyLinkedList */
  410. PHP_METHOD(SplDoublyLinkedList, unshift)
  411. {
  412. zval *value;
  413. spl_dllist_object *intern;
  414. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &value) == FAILURE) {
  415. RETURN_THROWS();
  416. }
  417. intern = Z_SPLDLLIST_P(ZEND_THIS);
  418. spl_ptr_llist_unshift(intern->llist, value);
  419. }
  420. /* }}} */
  421. /* {{{ Pop an element out of the SplDoublyLinkedList */
  422. PHP_METHOD(SplDoublyLinkedList, pop)
  423. {
  424. spl_dllist_object *intern;
  425. if (zend_parse_parameters_none() == FAILURE) {
  426. RETURN_THROWS();
  427. }
  428. intern = Z_SPLDLLIST_P(ZEND_THIS);
  429. spl_ptr_llist_pop(intern->llist, return_value);
  430. if (Z_ISUNDEF_P(return_value)) {
  431. zend_throw_exception(spl_ce_RuntimeException, "Can't pop from an empty datastructure", 0);
  432. RETURN_THROWS();
  433. }
  434. }
  435. /* }}} */
  436. /* {{{ Shift an element out of the SplDoublyLinkedList */
  437. PHP_METHOD(SplDoublyLinkedList, shift)
  438. {
  439. spl_dllist_object *intern;
  440. if (zend_parse_parameters_none() == FAILURE) {
  441. RETURN_THROWS();
  442. }
  443. intern = Z_SPLDLLIST_P(ZEND_THIS);
  444. spl_ptr_llist_shift(intern->llist, return_value);
  445. if (Z_ISUNDEF_P(return_value)) {
  446. zend_throw_exception(spl_ce_RuntimeException, "Can't shift from an empty datastructure", 0);
  447. RETURN_THROWS();
  448. }
  449. }
  450. /* }}} */
  451. /* {{{ Peek at the top element of the SplDoublyLinkedList */
  452. PHP_METHOD(SplDoublyLinkedList, top)
  453. {
  454. zval *value;
  455. spl_dllist_object *intern;
  456. if (zend_parse_parameters_none() == FAILURE) {
  457. RETURN_THROWS();
  458. }
  459. intern = Z_SPLDLLIST_P(ZEND_THIS);
  460. value = spl_ptr_llist_last(intern->llist);
  461. if (value == NULL || Z_ISUNDEF_P(value)) {
  462. zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty datastructure", 0);
  463. RETURN_THROWS();
  464. }
  465. RETURN_COPY_DEREF(value);
  466. }
  467. /* }}} */
  468. /* {{{ Peek at the bottom element of the SplDoublyLinkedList */
  469. PHP_METHOD(SplDoublyLinkedList, bottom)
  470. {
  471. zval *value;
  472. spl_dllist_object *intern;
  473. if (zend_parse_parameters_none() == FAILURE) {
  474. RETURN_THROWS();
  475. }
  476. intern = Z_SPLDLLIST_P(ZEND_THIS);
  477. value = spl_ptr_llist_first(intern->llist);
  478. if (value == NULL || Z_ISUNDEF_P(value)) {
  479. zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty datastructure", 0);
  480. RETURN_THROWS();
  481. }
  482. RETURN_COPY_DEREF(value);
  483. }
  484. /* }}} */
  485. /* {{{ Return the number of elements in the datastructure. */
  486. PHP_METHOD(SplDoublyLinkedList, count)
  487. {
  488. zend_long count;
  489. spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
  490. if (zend_parse_parameters_none() == FAILURE) {
  491. RETURN_THROWS();
  492. }
  493. count = spl_ptr_llist_count(intern->llist);
  494. RETURN_LONG(count);
  495. }
  496. /* }}} */
  497. /* {{{ Return true if the SplDoublyLinkedList is empty. */
  498. PHP_METHOD(SplDoublyLinkedList, isEmpty)
  499. {
  500. zend_long count;
  501. if (zend_parse_parameters_none() == FAILURE) {
  502. RETURN_THROWS();
  503. }
  504. spl_dllist_object_count_elements(Z_OBJ_P(ZEND_THIS), &count);
  505. RETURN_BOOL(count == 0);
  506. }
  507. /* }}} */
  508. /* {{{ Set the mode of iteration */
  509. PHP_METHOD(SplDoublyLinkedList, setIteratorMode)
  510. {
  511. zend_long value;
  512. spl_dllist_object *intern;
  513. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &value) == FAILURE) {
  514. RETURN_THROWS();
  515. }
  516. intern = Z_SPLDLLIST_P(ZEND_THIS);
  517. if ((intern->flags & SPL_DLLIST_IT_FIX)
  518. && (intern->flags & SPL_DLLIST_IT_LIFO) != (value & SPL_DLLIST_IT_LIFO)) {
  519. zend_throw_exception(spl_ce_RuntimeException, "Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen", 0);
  520. RETURN_THROWS();
  521. }
  522. intern->flags = (value & SPL_DLLIST_IT_MASK) | (intern->flags & SPL_DLLIST_IT_FIX);
  523. RETURN_LONG(intern->flags);
  524. }
  525. /* }}} */
  526. /* {{{ Return the mode of iteration */
  527. PHP_METHOD(SplDoublyLinkedList, getIteratorMode)
  528. {
  529. spl_dllist_object *intern;
  530. if (zend_parse_parameters_none() == FAILURE) {
  531. RETURN_THROWS();
  532. }
  533. intern = Z_SPLDLLIST_P(ZEND_THIS);
  534. RETURN_LONG(intern->flags);
  535. }
  536. /* }}} */
  537. /* {{{ Returns whether the requested $index exists. */
  538. PHP_METHOD(SplDoublyLinkedList, offsetExists)
  539. {
  540. spl_dllist_object *intern;
  541. zend_long index;
  542. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
  543. RETURN_THROWS();
  544. }
  545. intern = Z_SPLDLLIST_P(ZEND_THIS);
  546. RETURN_BOOL(index >= 0 && index < intern->llist->count);
  547. } /* }}} */
  548. /* {{{ Returns the value at the specified $index. */
  549. PHP_METHOD(SplDoublyLinkedList, offsetGet)
  550. {
  551. zend_long index;
  552. spl_dllist_object *intern;
  553. spl_ptr_llist_element *element;
  554. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
  555. RETURN_THROWS();
  556. }
  557. intern = Z_SPLDLLIST_P(ZEND_THIS);
  558. if (index < 0 || index >= intern->llist->count) {
  559. zend_argument_error(spl_ce_OutOfRangeException, 1, "is out of range");
  560. RETURN_THROWS();
  561. }
  562. element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
  563. if (element == NULL) {
  564. zend_argument_error(spl_ce_OutOfRangeException, 1, "is an invalid offset");
  565. RETURN_THROWS();
  566. }
  567. RETURN_COPY_DEREF(&element->data);
  568. } /* }}} */
  569. /* {{{ Sets the value at the specified $index to $newval. */
  570. PHP_METHOD(SplDoublyLinkedList, offsetSet)
  571. {
  572. zend_long index;
  573. bool index_is_null = 1;
  574. zval *value;
  575. spl_dllist_object *intern;
  576. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l!z", &index, &index_is_null, &value) == FAILURE) {
  577. RETURN_THROWS();
  578. }
  579. intern = Z_SPLDLLIST_P(ZEND_THIS);
  580. if (index_is_null) {
  581. /* $obj[] = ... */
  582. spl_ptr_llist_push(intern->llist, value);
  583. } else {
  584. /* $obj[$foo] = ... */
  585. spl_ptr_llist_element *element;
  586. if (index < 0 || index >= intern->llist->count) {
  587. zend_argument_error(spl_ce_OutOfRangeException, 1, "is out of range");
  588. RETURN_THROWS();
  589. }
  590. element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
  591. if (element != NULL) {
  592. /* the element is replaced, delref the old one as in
  593. * SplDoublyLinkedList::pop() */
  594. zval_ptr_dtor(&element->data);
  595. ZVAL_COPY(&element->data, value);
  596. } else {
  597. zval_ptr_dtor(value);
  598. zend_argument_error(spl_ce_OutOfRangeException, 1, "is an invalid offset");
  599. RETURN_THROWS();
  600. }
  601. }
  602. } /* }}} */
  603. /* {{{ Unsets the value at the specified $index. */
  604. PHP_METHOD(SplDoublyLinkedList, offsetUnset)
  605. {
  606. zend_long index;
  607. spl_dllist_object *intern;
  608. spl_ptr_llist_element *element;
  609. spl_ptr_llist *llist;
  610. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
  611. RETURN_THROWS();
  612. }
  613. intern = Z_SPLDLLIST_P(ZEND_THIS);
  614. llist = intern->llist;
  615. if (index < 0 || index >= intern->llist->count) {
  616. zend_argument_error(spl_ce_OutOfRangeException, 1, "is out of range");
  617. RETURN_THROWS();
  618. }
  619. element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
  620. if (element != NULL) {
  621. /* connect the neightbors */
  622. if (element->prev) {
  623. element->prev->next = element->next;
  624. }
  625. if (element->next) {
  626. element->next->prev = element->prev;
  627. }
  628. /* take care of head/tail */
  629. if (element == llist->head) {
  630. llist->head = element->next;
  631. }
  632. if (element == llist->tail) {
  633. llist->tail = element->prev;
  634. }
  635. /* finally, delete the element */
  636. llist->count--;
  637. if (intern->traverse_pointer == element) {
  638. SPL_LLIST_DELREF(element);
  639. intern->traverse_pointer = NULL;
  640. }
  641. zval_ptr_dtor(&element->data);
  642. ZVAL_UNDEF(&element->data);
  643. SPL_LLIST_DELREF(element);
  644. } else {
  645. zend_argument_error(spl_ce_OutOfRangeException, 1, "is an invalid offset");
  646. RETURN_THROWS();
  647. }
  648. } /* }}} */
  649. static void spl_dllist_it_dtor(zend_object_iterator *iter) /* {{{ */
  650. {
  651. spl_dllist_it *iterator = (spl_dllist_it *)iter;
  652. SPL_LLIST_CHECK_DELREF(iterator->traverse_pointer);
  653. zend_user_it_invalidate_current(iter);
  654. zval_ptr_dtor(&iterator->intern.it.data);
  655. }
  656. /* }}} */
  657. static void spl_dllist_it_helper_rewind(spl_ptr_llist_element **traverse_pointer_ptr, int *traverse_position_ptr, spl_ptr_llist *llist, int flags) /* {{{ */
  658. {
  659. SPL_LLIST_CHECK_DELREF(*traverse_pointer_ptr);
  660. if (flags & SPL_DLLIST_IT_LIFO) {
  661. *traverse_position_ptr = llist->count-1;
  662. *traverse_pointer_ptr = llist->tail;
  663. } else {
  664. *traverse_position_ptr = 0;
  665. *traverse_pointer_ptr = llist->head;
  666. }
  667. SPL_LLIST_CHECK_ADDREF(*traverse_pointer_ptr);
  668. }
  669. /* }}} */
  670. static void spl_dllist_it_helper_move_forward(spl_ptr_llist_element **traverse_pointer_ptr, int *traverse_position_ptr, spl_ptr_llist *llist, int flags) /* {{{ */
  671. {
  672. if (*traverse_pointer_ptr) {
  673. spl_ptr_llist_element *old = *traverse_pointer_ptr;
  674. if (flags & SPL_DLLIST_IT_LIFO) {
  675. *traverse_pointer_ptr = old->prev;
  676. (*traverse_position_ptr)--;
  677. if (flags & SPL_DLLIST_IT_DELETE) {
  678. zval prev;
  679. spl_ptr_llist_pop(llist, &prev);
  680. zval_ptr_dtor(&prev);
  681. }
  682. } else {
  683. *traverse_pointer_ptr = old->next;
  684. if (flags & SPL_DLLIST_IT_DELETE) {
  685. zval prev;
  686. spl_ptr_llist_shift(llist, &prev);
  687. zval_ptr_dtor(&prev);
  688. } else {
  689. (*traverse_position_ptr)++;
  690. }
  691. }
  692. SPL_LLIST_DELREF(old);
  693. SPL_LLIST_CHECK_ADDREF(*traverse_pointer_ptr);
  694. }
  695. }
  696. /* }}} */
  697. static void spl_dllist_it_rewind(zend_object_iterator *iter) /* {{{ */
  698. {
  699. spl_dllist_it *iterator = (spl_dllist_it *)iter;
  700. spl_dllist_object *object = Z_SPLDLLIST_P(&iter->data);
  701. spl_ptr_llist *llist = object->llist;
  702. spl_dllist_it_helper_rewind(&iterator->traverse_pointer, &iterator->traverse_position, llist, iterator->flags);
  703. }
  704. /* }}} */
  705. static int spl_dllist_it_valid(zend_object_iterator *iter) /* {{{ */
  706. {
  707. spl_dllist_it *iterator = (spl_dllist_it *)iter;
  708. spl_ptr_llist_element *element = iterator->traverse_pointer;
  709. return (element != NULL ? SUCCESS : FAILURE);
  710. }
  711. /* }}} */
  712. static zval *spl_dllist_it_get_current_data(zend_object_iterator *iter) /* {{{ */
  713. {
  714. spl_dllist_it *iterator = (spl_dllist_it *)iter;
  715. spl_ptr_llist_element *element = iterator->traverse_pointer;
  716. if (element == NULL || Z_ISUNDEF(element->data)) {
  717. return NULL;
  718. }
  719. return &element->data;
  720. }
  721. /* }}} */
  722. static void spl_dllist_it_get_current_key(zend_object_iterator *iter, zval *key) /* {{{ */
  723. {
  724. spl_dllist_it *iterator = (spl_dllist_it *)iter;
  725. ZVAL_LONG(key, iterator->traverse_position);
  726. }
  727. /* }}} */
  728. static void spl_dllist_it_move_forward(zend_object_iterator *iter) /* {{{ */
  729. {
  730. spl_dllist_it *iterator = (spl_dllist_it *)iter;
  731. spl_dllist_object *object = Z_SPLDLLIST_P(&iter->data);
  732. zend_user_it_invalidate_current(iter);
  733. spl_dllist_it_helper_move_forward(&iterator->traverse_pointer, &iterator->traverse_position, object->llist, iterator->flags);
  734. }
  735. /* }}} */
  736. /* {{{ Return current array key */
  737. PHP_METHOD(SplDoublyLinkedList, key)
  738. {
  739. spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
  740. if (zend_parse_parameters_none() == FAILURE) {
  741. RETURN_THROWS();
  742. }
  743. RETURN_LONG(intern->traverse_position);
  744. }
  745. /* }}} */
  746. /* {{{ Move to next entry */
  747. PHP_METHOD(SplDoublyLinkedList, prev)
  748. {
  749. spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
  750. if (zend_parse_parameters_none() == FAILURE) {
  751. RETURN_THROWS();
  752. }
  753. spl_dllist_it_helper_move_forward(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags ^ SPL_DLLIST_IT_LIFO);
  754. }
  755. /* }}} */
  756. /* {{{ Move to next entry */
  757. PHP_METHOD(SplDoublyLinkedList, next)
  758. {
  759. spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
  760. if (zend_parse_parameters_none() == FAILURE) {
  761. RETURN_THROWS();
  762. }
  763. spl_dllist_it_helper_move_forward(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags);
  764. }
  765. /* }}} */
  766. /* {{{ Check whether the datastructure contains more entries */
  767. PHP_METHOD(SplDoublyLinkedList, valid)
  768. {
  769. spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
  770. if (zend_parse_parameters_none() == FAILURE) {
  771. RETURN_THROWS();
  772. }
  773. RETURN_BOOL(intern->traverse_pointer != NULL);
  774. }
  775. /* }}} */
  776. /* {{{ Rewind the datastructure back to the start */
  777. PHP_METHOD(SplDoublyLinkedList, rewind)
  778. {
  779. spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
  780. if (zend_parse_parameters_none() == FAILURE) {
  781. RETURN_THROWS();
  782. }
  783. spl_dllist_it_helper_rewind(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags);
  784. }
  785. /* }}} */
  786. /* {{{ Return current datastructure entry */
  787. PHP_METHOD(SplDoublyLinkedList, current)
  788. {
  789. spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
  790. spl_ptr_llist_element *element = intern->traverse_pointer;
  791. if (zend_parse_parameters_none() == FAILURE) {
  792. RETURN_THROWS();
  793. }
  794. if (element == NULL || Z_ISUNDEF(element->data)) {
  795. RETURN_NULL();
  796. } else {
  797. RETURN_COPY_DEREF(&element->data);
  798. }
  799. }
  800. /* }}} */
  801. /* {{{ Serializes storage */
  802. PHP_METHOD(SplDoublyLinkedList, serialize)
  803. {
  804. spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
  805. smart_str buf = {0};
  806. spl_ptr_llist_element *current = intern->llist->head, *next;
  807. zval flags;
  808. php_serialize_data_t var_hash;
  809. if (zend_parse_parameters_none() == FAILURE) {
  810. RETURN_THROWS();
  811. }
  812. PHP_VAR_SERIALIZE_INIT(var_hash);
  813. /* flags */
  814. ZVAL_LONG(&flags, intern->flags);
  815. php_var_serialize(&buf, &flags, &var_hash);
  816. /* elements */
  817. while (current) {
  818. smart_str_appendc(&buf, ':');
  819. next = current->next;
  820. php_var_serialize(&buf, &current->data, &var_hash);
  821. current = next;
  822. }
  823. smart_str_0(&buf);
  824. /* done */
  825. PHP_VAR_SERIALIZE_DESTROY(var_hash);
  826. RETURN_NEW_STR(buf.s);
  827. } /* }}} */
  828. /* {{{ Unserializes storage */
  829. PHP_METHOD(SplDoublyLinkedList, unserialize)
  830. {
  831. spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
  832. zval *flags, *elem;
  833. char *buf;
  834. size_t buf_len;
  835. const unsigned char *p, *s;
  836. php_unserialize_data_t var_hash;
  837. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &buf, &buf_len) == FAILURE) {
  838. RETURN_THROWS();
  839. }
  840. if (buf_len == 0) {
  841. return;
  842. }
  843. while (intern->llist->count > 0) {
  844. zval tmp;
  845. spl_ptr_llist_pop(intern->llist, &tmp);
  846. zval_ptr_dtor(&tmp);
  847. }
  848. s = p = (const unsigned char*)buf;
  849. PHP_VAR_UNSERIALIZE_INIT(var_hash);
  850. /* flags */
  851. flags = var_tmp_var(&var_hash);
  852. if (!php_var_unserialize(flags, &p, s + buf_len, &var_hash) || Z_TYPE_P(flags) != IS_LONG) {
  853. goto error;
  854. }
  855. intern->flags = (int)Z_LVAL_P(flags);
  856. /* elements */
  857. while(*p == ':') {
  858. ++p;
  859. elem = var_tmp_var(&var_hash);
  860. if (!php_var_unserialize(elem, &p, s + buf_len, &var_hash)) {
  861. goto error;
  862. }
  863. var_push_dtor(&var_hash, elem);
  864. spl_ptr_llist_push(intern->llist, elem);
  865. }
  866. if (*p != '\0') {
  867. goto error;
  868. }
  869. PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
  870. return;
  871. error:
  872. PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
  873. zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Error at offset %zd of %zd bytes", ((char*)p - buf), buf_len);
  874. RETURN_THROWS();
  875. } /* }}} */
  876. /* {{{ */
  877. PHP_METHOD(SplDoublyLinkedList, __serialize)
  878. {
  879. spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
  880. spl_ptr_llist_element *current = intern->llist->head;
  881. zval tmp;
  882. if (zend_parse_parameters_none() == FAILURE) {
  883. RETURN_THROWS();
  884. }
  885. array_init(return_value);
  886. /* flags */
  887. ZVAL_LONG(&tmp, intern->flags);
  888. zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
  889. /* elements */
  890. array_init_size(&tmp, intern->llist->count);
  891. while (current) {
  892. zend_hash_next_index_insert(Z_ARRVAL(tmp), &current->data);
  893. Z_TRY_ADDREF(current->data);
  894. current = current->next;
  895. }
  896. zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
  897. /* members */
  898. ZVAL_ARR(&tmp, zend_proptable_to_symtable(
  899. zend_std_get_properties(&intern->std), /* always_duplicate */ 1));
  900. zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
  901. } /* }}} */
  902. /* {{{ */
  903. PHP_METHOD(SplDoublyLinkedList, __unserialize) {
  904. spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS);
  905. HashTable *data;
  906. zval *flags_zv, *storage_zv, *members_zv, *elem;
  907. if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &data) == FAILURE) {
  908. RETURN_THROWS();
  909. }
  910. flags_zv = zend_hash_index_find(data, 0);
  911. storage_zv = zend_hash_index_find(data, 1);
  912. members_zv = zend_hash_index_find(data, 2);
  913. if (!flags_zv || !storage_zv || !members_zv ||
  914. Z_TYPE_P(flags_zv) != IS_LONG || Z_TYPE_P(storage_zv) != IS_ARRAY ||
  915. Z_TYPE_P(members_zv) != IS_ARRAY) {
  916. zend_throw_exception(spl_ce_UnexpectedValueException,
  917. "Incomplete or ill-typed serialization data", 0);
  918. RETURN_THROWS();
  919. }
  920. intern->flags = (int) Z_LVAL_P(flags_zv);
  921. ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(storage_zv), elem) {
  922. spl_ptr_llist_push(intern->llist, elem);
  923. } ZEND_HASH_FOREACH_END();
  924. object_properties_load(&intern->std, Z_ARRVAL_P(members_zv));
  925. } /* }}} */
  926. /* {{{ Inserts a new entry before the specified $index consisting of $newval. */
  927. PHP_METHOD(SplDoublyLinkedList, add)
  928. {
  929. zval *value;
  930. spl_dllist_object *intern;
  931. spl_ptr_llist_element *element;
  932. zend_long index;
  933. if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz", &index, &value) == FAILURE) {
  934. RETURN_THROWS();
  935. }
  936. intern = Z_SPLDLLIST_P(ZEND_THIS);
  937. if (index < 0 || index > intern->llist->count) {
  938. zend_argument_error(spl_ce_OutOfRangeException, 1, "is out of range");
  939. RETURN_THROWS();
  940. }
  941. if (index == intern->llist->count) {
  942. /* If index is the last entry+1 then we do a push because we're not inserting before any entry */
  943. spl_ptr_llist_push(intern->llist, value);
  944. } else {
  945. /* Create the new element we want to insert */
  946. spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element));
  947. /* Get the element we want to insert before */
  948. element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
  949. ZVAL_COPY(&elem->data, value);
  950. SPL_LLIST_RC(elem) = 1;
  951. /* connect to the neighbours */
  952. elem->next = element;
  953. elem->prev = element->prev;
  954. /* connect the neighbours to this new element */
  955. if (elem->prev == NULL) {
  956. intern->llist->head = elem;
  957. } else {
  958. element->prev->next = elem;
  959. }
  960. element->prev = elem;
  961. intern->llist->count++;
  962. }
  963. } /* }}} */
  964. /* {{{ */
  965. PHP_METHOD(SplDoublyLinkedList, __debugInfo)
  966. {
  967. if (zend_parse_parameters_none() == FAILURE) {
  968. return;
  969. }
  970. RETURN_ARR(spl_dllist_object_get_debug_info(Z_OBJ_P(ZEND_THIS)));
  971. } /* }}} */
  972. /* {{{ iterator handler table */
  973. static const zend_object_iterator_funcs spl_dllist_it_funcs = {
  974. spl_dllist_it_dtor,
  975. spl_dllist_it_valid,
  976. spl_dllist_it_get_current_data,
  977. spl_dllist_it_get_current_key,
  978. spl_dllist_it_move_forward,
  979. spl_dllist_it_rewind,
  980. NULL,
  981. NULL, /* get_gc */
  982. }; /* }}} */
  983. zend_object_iterator *spl_dllist_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
  984. {
  985. spl_dllist_it *iterator;
  986. spl_dllist_object *dllist_object = Z_SPLDLLIST_P(object);
  987. if (by_ref) {
  988. zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
  989. return NULL;
  990. }
  991. iterator = emalloc(sizeof(spl_dllist_it));
  992. zend_iterator_init((zend_object_iterator*)iterator);
  993. ZVAL_OBJ_COPY(&iterator->intern.it.data, Z_OBJ_P(object));
  994. iterator->intern.it.funcs = &spl_dllist_it_funcs;
  995. iterator->intern.ce = ce;
  996. iterator->traverse_position = dllist_object->traverse_position;
  997. iterator->traverse_pointer = dllist_object->traverse_pointer;
  998. iterator->flags = dllist_object->flags & SPL_DLLIST_IT_MASK;
  999. ZVAL_UNDEF(&iterator->intern.value);
  1000. SPL_LLIST_CHECK_ADDREF(iterator->traverse_pointer);
  1001. return &iterator->intern.it;
  1002. }
  1003. /* }}} */
  1004. PHP_MINIT_FUNCTION(spl_dllist) /* {{{ */
  1005. {
  1006. spl_ce_SplDoublyLinkedList = register_class_SplDoublyLinkedList(
  1007. zend_ce_iterator, zend_ce_countable, zend_ce_arrayaccess, zend_ce_serializable
  1008. );
  1009. spl_ce_SplDoublyLinkedList->create_object = spl_dllist_object_new;
  1010. spl_ce_SplDoublyLinkedList->get_iterator = spl_dllist_get_iterator;
  1011. memcpy(&spl_handler_SplDoublyLinkedList, &std_object_handlers, sizeof(zend_object_handlers));
  1012. spl_handler_SplDoublyLinkedList.offset = XtOffsetOf(spl_dllist_object, std);
  1013. spl_handler_SplDoublyLinkedList.clone_obj = spl_dllist_object_clone;
  1014. spl_handler_SplDoublyLinkedList.count_elements = spl_dllist_object_count_elements;
  1015. spl_handler_SplDoublyLinkedList.get_gc = spl_dllist_object_get_gc;
  1016. spl_handler_SplDoublyLinkedList.free_obj = spl_dllist_object_free_storage;
  1017. REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_LIFO", SPL_DLLIST_IT_LIFO);
  1018. REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_FIFO", 0);
  1019. REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_DELETE",SPL_DLLIST_IT_DELETE);
  1020. REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_KEEP", 0);
  1021. spl_ce_SplQueue = register_class_SplQueue(spl_ce_SplDoublyLinkedList);
  1022. spl_ce_SplQueue->create_object = spl_dllist_object_new;
  1023. spl_ce_SplQueue->get_iterator = spl_dllist_get_iterator;
  1024. spl_ce_SplStack = register_class_SplStack(spl_ce_SplDoublyLinkedList);
  1025. spl_ce_SplStack->create_object = spl_dllist_object_new;
  1026. spl_ce_SplStack->get_iterator = spl_dllist_get_iterator;
  1027. return SUCCESS;
  1028. }
  1029. /* }}} */