├── ext-ds.ini
├── dev.sh
├── .valgrindrc
├── Dockerfile
├── docker-compose.yml
├── src
├── php
│ ├── classes
│ │ ├── php_hashable_ce.h
│ │ ├── php_deque_ce.h
│ │ ├── php_vector_ce.h
│ │ ├── php_pair_ce.h
│ │ ├── php_hashable_ce.c
│ │ ├── php_priority_queue_ce.h
│ │ ├── php_queue_ce.h
│ │ ├── php_stack_ce.h
│ │ ├── php_collection_ce.c
│ │ ├── php_collection_ce.h
│ │ ├── php_sequence_ce.c
│ │ ├── php_pair_ce.c
│ │ ├── php_set_ce.h
│ │ ├── php_map_ce.h
│ │ ├── php_priority_queue_ce.c
│ │ ├── php_sequence_ce.h
│ │ ├── php_stack_ce.c
│ │ ├── php_queue_ce.c
│ │ ├── php_set_ce.c
│ │ └── php_deque_ce.c
│ ├── handlers
│ │ ├── php_map_handlers.h
│ │ ├── php_set_handlers.h
│ │ ├── php_pair_handlers.h
│ │ ├── php_deque_handlers.h
│ │ ├── php_queue_handlers.h
│ │ ├── php_stack_handlers.h
│ │ ├── php_vector_handlers.h
│ │ ├── php_priority_queue_handlers.h
│ │ ├── php_common_handlers.h
│ │ ├── php_common_handlers.c
│ │ ├── php_pair_handlers.c
│ │ ├── php_priority_queue_handlers.c
│ │ ├── php_queue_handlers.c
│ │ ├── php_stack_handlers.c
│ │ ├── php_set_handlers.c
│ │ ├── php_map_handlers.c
│ │ ├── php_deque_handlers.c
│ │ └── php_vector_handlers.c
│ ├── iterators
│ │ ├── php_map_iterator.h
│ │ ├── php_set_iterator.h
│ │ ├── php_map_iterator.c
│ │ ├── php_set_iterator.c
│ │ ├── php_deque_iterator.h
│ │ ├── php_queue_iterator.h
│ │ ├── php_stack_iterator.h
│ │ ├── php_vector_iterator.h
│ │ ├── php_priority_queue_iterator.h
│ │ ├── php_htable_iterator.h
│ │ ├── php_deque_iterator.c
│ │ ├── php_vector_iterator.c
│ │ ├── php_queue_iterator.c
│ │ ├── php_stack_iterator.c
│ │ ├── php_priority_queue_iterator.c
│ │ └── php_htable_iterator.c
│ ├── objects
│ │ ├── php_set.h
│ │ ├── php_stack.h
│ │ ├── php_queue.h
│ │ ├── php_vector.h
│ │ ├── php_map.h
│ │ ├── php_pair.h
│ │ ├── php_deque.h
│ │ ├── php_priority_queue.h
│ │ ├── php_map.c
│ │ ├── php_set.c
│ │ ├── php_deque.c
│ │ ├── php_queue.c
│ │ ├── php_stack.c
│ │ ├── php_vector.c
│ │ ├── php_priority_queue.c
│ │ └── php_pair.c
│ └── parameters.h
├── ds
│ ├── ds_queue.h
│ ├── ds_stack.h
│ ├── ds_stack.c
│ ├── ds_queue.c
│ ├── ds_set.h
│ ├── ds_map.h
│ ├── ds_priority_queue.h
│ ├── ds_deque.h
│ └── ds_vector.h
└── common.c
├── phpunit.xml
├── .editorconfig
├── test.php
├── .gitignore
├── composer.json
├── LICENSE
├── sandbox.php
├── CONTRIBUTING.md
├── .github
└── workflows
│ └── main.yml
├── php_ds.h
├── php_ds.c
├── config.w32
├── README.md
├── appveyor.yml
├── config.m4
└── CHANGELOG.md
/ext-ds.ini:
--------------------------------------------------------------------------------
1 | extension=ds.so
--------------------------------------------------------------------------------
/dev.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | docker-compose run --rm --build --interactive --tty dev /bin/sh
--------------------------------------------------------------------------------
/.valgrindrc:
--------------------------------------------------------------------------------
1 | --memcheck:leak-check=full
2 | --memcheck:track-origins=yes
3 | --memcheck:error-exitcode=1
4 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.4-alpine
2 |
3 | RUN apk add --no-cache $PHPIZE_DEPS valgrind
4 |
5 | COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
6 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | dev:
3 | build:
4 | context: "."
5 | volumes:
6 | - ".:/ext-ds"
7 | - "./ext-ds.ini:/usr/local/etc/php/conf.d/ext-ds.ini"
8 | working_dir: "/ext-ds"
--------------------------------------------------------------------------------
/src/php/classes/php_hashable_ce.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_HASHABLE_CE_H
2 | #define DS_HASHABLE_CE_H
3 |
4 | #include "php.h"
5 |
6 | extern zend_class_entry *hashable_ce;
7 |
8 | void php_ds_register_hashable();
9 |
10 | #endif
11 |
--------------------------------------------------------------------------------
/src/php/handlers/php_map_handlers.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_MAP_HANDLERS_H
2 | #define DS_MAP_HANDLERS_H
3 |
4 | #include "php.h"
5 |
6 | extern zend_object_handlers php_map_handlers;
7 |
8 | void php_ds_register_map_handlers();
9 |
10 | #endif
11 |
--------------------------------------------------------------------------------
/src/php/handlers/php_set_handlers.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_SET_HANDLERS_H
2 | #define DS_SET_HANDLERS_H
3 |
4 | #include "php.h"
5 |
6 | extern zend_object_handlers php_ds_set_handlers;
7 |
8 | void php_ds_register_set_handlers();
9 |
10 | #endif
11 |
--------------------------------------------------------------------------------
/src/php/handlers/php_pair_handlers.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_PAIR_HANDLERS_H
2 | #define DS_PAIR_HANDLERS_H
3 |
4 | #include "php.h"
5 |
6 | extern zend_object_handlers php_pair_handlers;
7 |
8 | void php_ds_register_pair_handlers();
9 |
10 | #endif
11 |
--------------------------------------------------------------------------------
/src/php/handlers/php_deque_handlers.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_DEQUE_HANDLERS_H
2 | #define DS_DEQUE_HANDLERS_H
3 |
4 | #include "php.h"
5 |
6 | extern zend_object_handlers php_deque_handlers;
7 |
8 | void php_ds_register_deque_handlers();
9 |
10 | #endif
11 |
--------------------------------------------------------------------------------
/src/php/handlers/php_queue_handlers.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_QUEUE_HANDLERS_H
2 | #define DS_QUEUE_HANDLERS_H
3 |
4 | #include "php.h"
5 |
6 | extern zend_object_handlers php_queue_handlers;
7 |
8 | void php_ds_register_queue_handlers();
9 |
10 | #endif
11 |
--------------------------------------------------------------------------------
/src/php/handlers/php_stack_handlers.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_STACK_HANDLERS_H
2 | #define DS_STACK_HANDLERS_H
3 |
4 | #include "php.h"
5 |
6 | extern zend_object_handlers php_ds_stack_handlers;
7 |
8 | void php_register_ds_stack_handlers();
9 |
10 | #endif
11 |
--------------------------------------------------------------------------------
/src/php/handlers/php_vector_handlers.h:
--------------------------------------------------------------------------------
1 | #ifndef PHP_DS_VECTOR_HANDLERS_H
2 | #define PHP_DS_VECTOR_HANDLERS_H
3 |
4 | #include "php.h"
5 |
6 | extern zend_object_handlers php_vector_handlers;
7 |
8 | void php_register_vector_handlers();
9 |
10 | #endif
11 |
--------------------------------------------------------------------------------
/src/php/iterators/php_map_iterator.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_MAP_ITERATOR_H
2 | #define DS_MAP_ITERATOR_H
3 |
4 | #include "php.h"
5 |
6 | /**
7 | *
8 | */
9 | zend_object_iterator *php_ds_map_get_iterator(zend_class_entry *ce, zval *obj, int by_ref);
10 |
11 | #endif
12 |
--------------------------------------------------------------------------------
/src/php/handlers/php_priority_queue_handlers.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_PRIORITY_QUEUE_HANDLERS_H
2 | #define DS_PRIORITY_QUEUE_HANDLERS_H
3 |
4 | #include "php.h"
5 |
6 | extern zend_object_handlers php_priority_queue_handlers;
7 |
8 | void php_ds_register_priority_queue_handlers();
9 |
10 | #endif
11 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 | vendor/php-ds/tests/tests
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/php/iterators/php_set_iterator.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_SET_ITERATOR_H
2 | #define DS_SET_ITERATOR_H
3 |
4 | #include "php.h"
5 | #include "../../ds/ds_set.h"
6 |
7 | /**
8 | *
9 | */
10 | zend_object_iterator *php_ds_set_get_iterator(zend_class_entry *ce, zval *object, int by_ref);
11 |
12 | #endif
13 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # This file is for unifying the coding style for different editors and IDEs.
2 | # More information at http://editorconfig.org
3 |
4 | root = true
5 |
6 | [*]
7 | end_of_line = lf
8 |
9 | [*.{php, c, h}]
10 | indent_style = space
11 | indent_size = 4
12 | trim_trailing_whitespace = true
13 |
--------------------------------------------------------------------------------
/src/php/classes/php_deque_ce.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_DEQUE_CE_H
2 | #define DS_DEQUE_CE_H
3 |
4 | #include "php.h"
5 | #include "../../common.h"
6 | #include "../arginfo.h"
7 |
8 | extern zend_class_entry *php_ds_deque_ce;
9 |
10 | ARGINFO_OPTIONAL_ZVAL(Deque___construct, values);
11 | ARGINFO_NONE_RETURN_OBJ(Deque_getIterator, Traversable);
12 |
13 |
14 | void php_ds_register_deque();
15 |
16 | #endif
17 |
--------------------------------------------------------------------------------
/src/php/classes/php_vector_ce.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_VECTOR_CE_H
2 | #define DS_VECTOR_CE_H
3 |
4 | #include "php.h"
5 | #include "../../common.h"
6 | #include "../arginfo.h"
7 |
8 | extern zend_class_entry *php_ds_vector_ce;
9 |
10 | ARGINFO_OPTIONAL_ZVAL(Vector___construct, values);
11 | ARGINFO_NONE_RETURN_OBJ(Vector_getIterator, Traversable);
12 |
13 | void php_ds_register_vector();
14 |
15 | #endif
16 |
--------------------------------------------------------------------------------
/src/php/iterators/php_map_iterator.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 |
3 | #include "../../ds/ds_map.h"
4 | #include "../../ds/ds_htable.h"
5 | #include "../objects/php_map.h"
6 |
7 | #include "php_map_iterator.h"
8 | #include "php_htable_iterator.h"
9 |
10 | zend_object_iterator *php_ds_map_get_iterator(zend_class_entry *ce, zval *obj, int by_ref)
11 | {
12 | ds_htable_t *table = Z_DS_MAP_P(obj)->table;
13 | return php_ds_htable_get_assoc_iterator_ex(ce, obj, by_ref, table);
14 | }
15 |
--------------------------------------------------------------------------------
/src/php/iterators/php_set_iterator.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 |
3 | #include "../../ds/ds_set.h"
4 | #include "../../ds/ds_htable.h"
5 | #include "../objects/php_set.h"
6 |
7 | #include "php_set_iterator.h"
8 | #include "php_htable_iterator.h"
9 |
10 | zend_object_iterator *php_ds_set_get_iterator(zend_class_entry *ce, zval *obj, int by_ref)
11 | {
12 | ds_htable_t *table = (Z_DS_SET_P(obj))->table;
13 | return php_ds_htable_get_key_iterator_ex(ce, obj, by_ref, table);
14 | }
15 |
--------------------------------------------------------------------------------
/src/php/iterators/php_deque_iterator.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_DEQUE_ITERATOR_H
2 | #define DS_DEQUE_ITERATOR_H
3 |
4 | #include "php.h"
5 | #include "../../ds/ds_deque.h"
6 |
7 | typedef struct php_ds_deque_iterator {
8 | zend_object_iterator intern;
9 | zend_object *object;
10 | ds_deque_t *deque;
11 | zend_long position;
12 | } php_ds_deque_iterator_t;
13 |
14 | zend_object_iterator *php_ds_deque_get_iterator(zend_class_entry *ce, zval *obj, int by_ref);
15 |
16 | #endif
17 |
--------------------------------------------------------------------------------
/src/php/iterators/php_queue_iterator.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_QUEUE_ITERATOR_H
2 | #define DS_QUEUE_ITERATOR_H
3 |
4 | #include "php.h"
5 | #include "../objects/php_queue.h"
6 |
7 | typedef struct _ds_queue_iterator_t {
8 | zend_object_iterator intern;
9 | zend_long position;
10 | zend_object *object;
11 | ds_queue_t *queue;
12 | } ds_queue_iterator_t;
13 |
14 | zend_object_iterator *php_ds_queue_get_iterator(zend_class_entry *ce, zval *object, int by_ref);
15 |
16 | #endif
17 |
--------------------------------------------------------------------------------
/src/php/iterators/php_stack_iterator.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_STACK_ITERATOR_H
2 | #define DS_STACK_ITERATOR_H
3 |
4 | #include "php.h"
5 | #include "../objects/php_stack.h"
6 |
7 | typedef struct _php_ds_stack_iterator_t {
8 | zend_object_iterator intern;
9 | zend_long position;
10 | zend_object *object;
11 | ds_stack_t *stack;
12 | } php_ds_stack_iterator_t;
13 |
14 | zend_object_iterator *php_ds_stack_get_iterator(zend_class_entry *ce, zval *object, int by_ref);
15 |
16 | #endif
17 |
--------------------------------------------------------------------------------
/src/php/iterators/php_vector_iterator.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_VECTOR_ITERATOR_H
2 | #define DS_VECTOR_ITERATOR_H
3 |
4 | #include "php.h"
5 | #include "../../ds/ds_vector.h"
6 |
7 | typedef struct php_ds_vector_iterator {
8 | zend_object_iterator intern;
9 | zend_object *object;
10 | ds_vector_t *vector;
11 | zend_long position;
12 | } php_ds_vector_iterator_t;
13 |
14 | zend_object_iterator *php_ds_vector_get_iterator(zend_class_entry *ce, zval *obj, int by_ref);
15 |
16 | #endif
17 |
--------------------------------------------------------------------------------
/src/php/classes/php_pair_ce.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_PAIR_CE_H
2 | #define DS_PAIR_CE_H
3 |
4 | #include "php.h"
5 | #include "../../common.h"
6 | #include "../arginfo.h"
7 |
8 | extern zend_class_entry *php_ds_pair_ce;
9 |
10 | ARGINFO_OPTIONAL_ZVAL_OPTIONAL_ZVAL( Pair___construct, key, value);
11 | ARGINFO_NONE_RETURN_DS( Pair_copy, Pair);
12 | ARGINFO_NONE_RETURN_ARRAY( Pair_toArray);
13 | ARGINFO_NONE_RETURN_TYPE( Pair_jsonSerialize, IS_MIXED);
14 |
15 | void php_ds_register_pair();
16 |
17 | #endif
18 |
--------------------------------------------------------------------------------
/src/php/iterators/php_priority_queue_iterator.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_PRIORITY_QUEUE_ITERATOR_H
2 | #define DS_PRIORITY_QUEUE_ITERATOR_H
3 |
4 | #include "php.h"
5 | #include "../../ds/ds_priority_queue.h"
6 |
7 | typedef struct _php_ds_priority_queue_iterator {
8 | zend_object_iterator intern;
9 | zend_object *object;
10 | ds_priority_queue_t *queue;
11 | zend_long position;
12 | } php_ds_priority_queue_iterator;
13 |
14 | zend_object_iterator *php_ds_priority_queue_get_iterator(zend_class_entry *ce, zval *object, int by_ref);
15 |
16 | #endif
17 |
--------------------------------------------------------------------------------
/src/php/classes/php_hashable_ce.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 | #include "../arginfo.h"
3 |
4 | #include "php_hashable_ce.h"
5 |
6 | zend_class_entry *hashable_ce;
7 |
8 | ARGINFO_NONE(hash);
9 | ARGINFO_ZVAL_RETURN_BOOL(equals, obj);
10 |
11 | static zend_function_entry hashable_methods[] = {
12 | PHP_ABSTRACT_ME(Hashable, hash, arginfo_hash)
13 | PHP_ABSTRACT_ME(Hashable, equals, arginfo_equals)
14 | PHP_FE_END
15 | };
16 |
17 | void php_ds_register_hashable()
18 | {
19 | zend_class_entry ce;
20 | INIT_CLASS_ENTRY(ce, PHP_DS_NS(Hashable), hashable_methods);
21 | hashable_ce = zend_register_internal_interface(&ce);
22 | }
23 |
--------------------------------------------------------------------------------
/test.php:
--------------------------------------------------------------------------------
1 | = 7.4.0"
16 | },
17 | "require-dev": {
18 | "php-ds/tests": "^1.5"
19 | },
20 | "scripts": {
21 | "test" : "php test.php",
22 | "memtest": "USE_ZEND_ALLOC=0 ZEND_DONT_UNLOAD_MODULES=1 valgrind php test.php"
23 | },
24 | "php-ext": {
25 | "extension-name": "ds"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/php/classes/php_priority_queue_ce.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_PRIORITY_QUEUE_CE_H
2 | #define DS_PRIORITY_QUEUE_CE_H
3 |
4 | #include "php.h"
5 | #include "../../common.h"
6 | #include "../arginfo.h"
7 |
8 | extern zend_class_entry *php_ds_priority_queue_ce;
9 |
10 | ARGINFO_NONE( PriorityQueue___construct);
11 | ARGINFO_LONG( PriorityQueue_allocate, capacity);
12 | ARGINFO_NONE_RETURN_LONG( PriorityQueue_capacity);
13 | ARGINFO_NONE_RETURN_DS( PriorityQueue_copy, PriorityQueue);
14 | ARGINFO_ZVAL_ZVAL( PriorityQueue_push, value, priority);
15 | ARGINFO_NONE( PriorityQueue_pop);
16 | ARGINFO_NONE( PriorityQueue_peek);
17 | ARGINFO_NONE_RETURN_OBJ( PriorityQueue_getIterator, Traversable);
18 |
19 | void php_ds_register_priority_queue();
20 |
21 | #endif
22 |
--------------------------------------------------------------------------------
/src/php/classes/php_queue_ce.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_QUEUE_CE_H
2 | #define DS_QUEUE_CE_H
3 |
4 | #include "php.h"
5 | #include "../../common.h"
6 | #include "../arginfo.h"
7 |
8 | extern zend_class_entry *php_ds_queue_ce;
9 |
10 | ARGINFO_OPTIONAL_ZVAL( Queue___construct, values);
11 | ARGINFO_LONG( Queue_allocate, capacity);
12 | ARGINFO_NONE_RETURN_LONG( Queue_capacity);
13 | ARGINFO_VARIADIC_ZVAL( Queue_push, values);
14 | ARGINFO_NONE( Queue_pop);
15 | ARGINFO_NONE( Queue_peek);
16 | ARGINFO_NONE_RETURN_OBJ( Queue_getIterator, Traversable);
17 |
18 | ARGINFO_ZVAL_RETURN_BOOL( Queue_offsetExists, offset);
19 | ARGINFO_OFFSET_GET( Queue_offsetGet);
20 | ARGINFO_OFFSET_SET( Queue_offsetSet);
21 | ARGINFO_OFFSET_UNSET( Queue_offsetUnset);
22 |
23 | void php_ds_register_queue();
24 |
25 | #endif
26 |
--------------------------------------------------------------------------------
/src/php/classes/php_stack_ce.h:
--------------------------------------------------------------------------------
1 | #ifndef PHP_DS_STACK_CE_H
2 | #define PHP_DS_STACK_CE_H
3 |
4 | #include "php.h"
5 | #include "../../common.h"
6 | #include "../arginfo.h"
7 |
8 | extern zend_class_entry *php_ds_stack_ce;
9 |
10 | ARGINFO_OPTIONAL_ZVAL( Stack___construct, values);
11 | ARGINFO_LONG( Stack_allocate, capacity);
12 | ARGINFO_NONE_RETURN_LONG( Stack_capacity);
13 | ARGINFO_VARIADIC_ZVAL( Stack_push, values);
14 | ARGINFO_NONE( Stack_pop);
15 | ARGINFO_NONE( Stack_peek);
16 | ARGINFO_NONE_RETURN_OBJ( Stack_getIterator, Traversable);
17 |
18 | ARGINFO_ZVAL_RETURN_BOOL( Stack_offsetExists, offset);
19 | ARGINFO_OFFSET_GET( Stack_offsetGet);
20 | ARGINFO_OFFSET_SET( Stack_offsetSet);
21 | ARGINFO_OFFSET_UNSET( Stack_offsetUnset);
22 |
23 | void php_ds_register_stack();
24 |
25 | #endif
26 |
--------------------------------------------------------------------------------
/src/php/iterators/php_htable_iterator.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_HTABLE_ITERATOR_H
2 | #define DS_HTABLE_ITERATOR_H
3 |
4 | #include "php.h"
5 | #include "../../ds/ds_htable.h"
6 |
7 | typedef struct ds_htable_iterator {
8 |
9 | zend_object_iterator intern;
10 | uint32_t position;
11 | ds_htable_bucket_t *bucket;
12 | ds_htable_t *table;
13 | zend_object *obj;
14 |
15 | } ds_htable_iterator_t;
16 |
17 | zend_object_iterator *php_ds_htable_get_value_iterator_ex(zend_class_entry *ce, zval *obj, int by_ref, ds_htable_t *h);
18 | zend_object_iterator *php_ds_htable_get_key_iterator_ex (zend_class_entry *ce, zval *obj, int by_ref, ds_htable_t *h);
19 | zend_object_iterator *php_ds_htable_get_pair_iterator_ex (zend_class_entry *ce, zval *obj, int by_ref, ds_htable_t *h);
20 | zend_object_iterator *php_ds_htable_get_assoc_iterator_ex(zend_class_entry *ce, zval *obj, int by_ref, ds_htable_t *h);
21 |
22 | #endif
23 |
--------------------------------------------------------------------------------
/src/php/classes/php_collection_ce.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 | #include "php_collection_ce.h"
3 |
4 | zend_class_entry *collection_ce;
5 |
6 | #define COLLECTION_ABSTRACT_ME(name) \
7 | PHP_ABSTRACT_ME(Collection, name, arginfo_Collection_##name)
8 |
9 | void php_ds_register_collection()
10 | {
11 | zend_class_entry ce;
12 |
13 | zend_function_entry methods[] = {
14 | COLLECTION_ABSTRACT_ME(clear)
15 | COLLECTION_ABSTRACT_ME(copy)
16 | COLLECTION_ABSTRACT_ME(isEmpty)
17 | COLLECTION_ABSTRACT_ME(toArray)
18 | PHP_FE_END
19 | };
20 |
21 | INIT_CLASS_ENTRY(ce, PHP_DS_NS(Collection), methods);
22 |
23 | collection_ce = zend_register_internal_interface(&ce);
24 |
25 | zend_class_implements(collection_ce, 3,
26 | zend_ce_aggregate, // IteratorAggregate
27 | spl_ce_Countable, // Countable
28 | php_json_serializable_ce // Serializable
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/src/php/handlers/php_common_handlers.h:
--------------------------------------------------------------------------------
1 | #ifndef PHP_COMMON_HANDLERS_H
2 | #define PHP_COMMON_HANDLERS_H
3 |
4 | #include "php.h"
5 |
6 | /**
7 | * Default object cast handler.
8 | */
9 | int php_ds_default_cast_object
10 | #if PHP_VERSION_ID >= 80000
11 | (zend_object *obj, zval *return_value, int type);
12 | #else
13 | (zval *obj, zval *return_value, int type);
14 | #endif
15 |
16 | zval *php_ds_read_dimension_by_key_not_supported
17 | #if PHP_VERSION_ID >= 80000
18 | (zend_object *obj, zval *offset, int type, zval *rv);
19 | #else
20 | (zval *obj, zval *offset, int type, zval *rv);
21 | #endif
22 |
23 | int php_ds_has_dimension_by_key_not_supported
24 | #if PHP_VERSION_ID >= 80000
25 | (zend_object *obj, zval *offset, int check_empty);
26 | #else
27 | (zval *obj, zval *offset, int check_empty);
28 | #endif
29 |
30 | void php_ds_unset_dimension_by_key_not_supported
31 | #if PHP_VERSION_ID >= 80000
32 | (zend_object *obj, zval *offset);
33 | #else
34 | (zval *obj, zval *offset);
35 | #endif
36 |
37 | #endif
--------------------------------------------------------------------------------
/src/php/classes/php_collection_ce.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_COLLECTION_CE_H
2 | #define DS_COLLECTION_CE_H
3 |
4 | #include "../../common.h"
5 | #include "../arginfo.h"
6 |
7 | extern zend_class_entry *collection_ce;
8 |
9 | #define PHP_DS_COLLECTION_ME(cls, name) \
10 | PHP_ME(cls, name, arginfo_Collection_##name, ZEND_ACC_PUBLIC)
11 |
12 | #define PHP_DS_COLLECTION_ME_LIST(cls) \
13 | PHP_DS_COLLECTION_ME(cls, clear) \
14 | PHP_DS_COLLECTION_ME(cls, copy) \
15 | PHP_DS_COLLECTION_ME(cls, count) \
16 | PHP_DS_COLLECTION_ME(cls, isEmpty) \
17 | PHP_DS_COLLECTION_ME(cls, jsonSerialize) \
18 | PHP_DS_COLLECTION_ME(cls, toArray)
19 |
20 | ARGINFO_NONE_RETURN_DS( Collection_copy, Collection);
21 | ARGINFO_NONE( Collection_clear);
22 | ARGINFO_NONE_RETURN_LONG( Collection_count);
23 | ARGINFO_NONE_RETURN_BOOL( Collection_isEmpty);
24 | ARGINFO_NONE_RETURN_TYPE( Collection_jsonSerialize, IS_MIXED);
25 | ARGINFO_NONE_RETURN_ARRAY( Collection_toArray);
26 |
27 | void php_ds_register_collection();
28 |
29 | #endif
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2016 Rudi Theunissen
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a
5 | copy of this software and associated documentation files (the "Software"),
6 | to deal in the Software without restriction, including without limitation
7 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 | and/or sell copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
20 | THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/sandbox.php:
--------------------------------------------------------------------------------
1 | push(new DateTime());
5 |
6 | $sequence = $vector->map(function (DateTime $_dateTime) { return $_dateTime->format(DateTime::ISO8601);});
7 |
8 | $sequence->push(new DateTime());
9 | $sequence->push(new DateTime());
10 |
11 | $sequence->push(new DateTime());
12 | $sequence->push(new DateTime());
13 |
14 | $sequence->push(new DateTime());
15 | $sequence->push(new DateTime());
16 |
17 | $sequence->push(new DateTime());
18 | $sequence->push(new DateTime());
19 | $sequence->push(new DateTime());
20 | $sequence->push(new DateTime());
21 | $sequence->push(new DateTime());
22 | $sequence->push(new DateTime());
23 | $sequence->push(new DateTime());
24 | $sequence->push(new DateTime());
25 | $sequence->push(new DateTime());
26 | $sequence->push(new DateTime());
27 | $sequence->push(new DateTime());
28 | $sequence->push(new DateTime());
29 | $sequence->push(new DateTime());
30 | $sequence->push(new DateTime());
31 | $sequence->push(new DateTime());
32 | $sequence->push(new DateTime());
33 | $sequence->push(new DateTime());
34 | $sequence->push(new DateTime());
35 |
36 | var_dump($sequence);
37 |
38 | echo 'done';
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Contributions are accepted via [pull requests](https://github.com/php-ds/ext/pulls). If you would like to report a bug, please create an [issue](https://github.com/php-ds/ext/issues) instead.
4 |
5 | ## Issues
6 |
7 | - **How to reproduce** - Provide an easy way to reproduce the bug. This makes it easier for others to debug.
8 |
9 | - **Platform details** - Specify your platform and your PHP version, eg. "PHP 7.0.2 on Ubuntu 14.04 64x".
10 |
11 | ## Pull Requests
12 |
13 | - **Add tests** - Your patch won't be accepted if it doesn't have tests where appropriate.
14 |
15 | - **Document any change in behaviour** - Make sure the README and any other relevant documentation updated.
16 |
17 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
18 |
19 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting.
20 |
21 | - **Coding style** - Try to match the style of the rest of the source wherever possible. Your patch won't be accepted if the style is significantly different.
22 |
--------------------------------------------------------------------------------
/src/php/objects/php_set.h:
--------------------------------------------------------------------------------
1 | #ifndef PHP_DS_SET_H
2 | #define PHP_DS_SET_H
3 |
4 | #include "../../ds/ds_set.h"
5 |
6 | typedef struct _php_ds_set_t {
7 | ds_set_t *set;
8 | zend_object std;
9 | } php_ds_set_t;
10 |
11 | static inline php_ds_set_t *php_ds_set_fetch_object(zend_object *obj) {
12 | return (php_ds_set_t *)((char*)(obj) - XtOffsetOf(php_ds_set_t, std));
13 | }
14 |
15 | #define Z_DS_SET(z) (php_ds_set_fetch_object(Z_OBJ(z))->set)
16 | #define Z_DS_SET_P(z) Z_DS_SET(*z)
17 | #define THIS_DS_SET() Z_DS_SET_P(getThis())
18 |
19 | #define ZVAL_DS_SET(z, set) ZVAL_OBJ(z, php_ds_set_create_object_ex(set))
20 |
21 | #define RETURN_DS_SET(s) \
22 | do { \
23 | ds_set_t *_s = s; \
24 | if (_s) { \
25 | ZVAL_DS_SET(return_value, _s); \
26 | } else { \
27 | ZVAL_NULL(return_value); \
28 | } \
29 | return; \
30 | } while(0)
31 |
32 | zend_object *php_ds_set_create_object_ex(ds_set_t *set);
33 | zend_object *php_ds_set_create_object(zend_class_entry *ce);
34 | zend_object *php_ds_set_create_clone(ds_set_t *set);
35 |
36 | PHP_DS_SERIALIZE_FUNCIONS(php_ds_set);
37 |
38 | #endif
39 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | pull_request:
5 | push:
6 | branches:
7 | - "master"
8 | workflow_dispatch:
9 |
10 | jobs:
11 | build:
12 | name: PHP ${{ matrix.php }} PHPTS ${{ matrix.phpts }} OPcache ${{ matrix.opcache }}
13 | runs-on: ubuntu-22.04
14 | strategy:
15 | fail-fast: false
16 | matrix:
17 | php:
18 | - "7.4"
19 | - "8.0"
20 | - "8.1"
21 | - "8.2"
22 | - "8.3"
23 | - "8.4"
24 | phpts: ["ts", "nts"]
25 | opcache: [1, 0]
26 |
27 | steps:
28 | - uses: actions/checkout@v2
29 |
30 | - name: Setup PHP
31 | uses: shivammathur/setup-php@v2
32 | with:
33 | php-version: ${{ matrix.php }}
34 | ini-values: opcache.enable_cli=${{ matrix.opcache }}
35 | env:
36 | phpts: ${{ matrix.phpts }}
37 |
38 | - name: Install extension
39 | working-directory: ${{ github.workspace }}
40 | run: |
41 | phpize
42 | ./configure --with-php-config=/usr/bin/php-config
43 | sudo make -j8 install
44 |
45 | - name: "Install dependencies with Composer"
46 | uses: "ramsey/composer-install@v3"
47 | with:
48 | composer-options: "--prefer-dist"
49 |
50 | - name: Run PHPUnit tests
51 | run: composer test
52 |
--------------------------------------------------------------------------------
/php_ds.h:
--------------------------------------------------------------------------------
1 | #ifndef PHP_DS_H
2 | #define PHP_DS_H
3 |
4 | #include
5 |
6 | #include "php.h"
7 | #include "main/php.h"
8 | #include "zend_exceptions.h"
9 | #include "zend_interfaces.h"
10 | #include "zend_operators.h"
11 | #include "ext/standard/info.h"
12 | #include "ext/standard/php_var.h"
13 | #include "ext/spl/spl_iterators.h"
14 | #include "ext/spl/spl_exceptions.h"
15 | #include "zend_smart_str.h"
16 | #include "ext/json/php_json.h"
17 |
18 | extern zend_module_entry ds_module_entry;
19 |
20 | #define phpext_ds_ptr &ds_module_entry
21 |
22 | /* Replace with version number for your extension */
23 | #define PHP_DS_VERSION "1.6.0"
24 |
25 | #ifdef PHP_WIN32
26 | # define PHP_API __declspec(dllexport)
27 | #elif defined(__GNUC__) && __GNUC__ >= 4
28 | # define PHP_API __attribute__ ((visibility("default")))
29 | #else
30 | # define PHP_API
31 | #endif
32 |
33 | #ifdef ZTS
34 | #include "TSRM.h"
35 | #endif
36 |
37 | ZEND_BEGIN_MODULE_GLOBALS(ds)
38 | zend_fcall_info user_compare_fci;
39 | zend_fcall_info_cache user_compare_fci_cache;
40 | ZEND_END_MODULE_GLOBALS(ds)
41 |
42 | #ifdef ZTS
43 | #define DSG(v) TSRMG(ds_globals_id, zend_ds_globals *, v)
44 | #else
45 | #define DSG(v) (ds_globals.v)
46 | #endif
47 |
48 | ZEND_EXTERN_MODULE_GLOBALS(ds);
49 |
50 | #if defined(ZTS) && defined(COMPILE_DL_DS)
51 | ZEND_TSRMLS_CACHE_EXTERN();
52 | #endif
53 |
54 | #endif
55 |
--------------------------------------------------------------------------------
/src/php/objects/php_stack.h:
--------------------------------------------------------------------------------
1 | #ifndef PHP_DS_STACK_H
2 | #define PHP_DS_STACK_H
3 |
4 | #include "../../ds/ds_stack.h"
5 |
6 | typedef struct _php_ds_stack_t {
7 | ds_stack_t *stack;
8 | zend_object std;
9 | } php_ds_stack_t;
10 |
11 | static inline php_ds_stack_t *php_ds_stack_fetch_object(zend_object *obj) {
12 | return (php_ds_stack_t *)((char*)(obj) - XtOffsetOf(php_ds_stack_t, std));
13 | }
14 |
15 | #define Z_DS_STACK(z) php_ds_stack_fetch_object(Z_OBJ(z))->stack
16 | #define Z_DS_STACK_P(z) Z_DS_STACK(*z)
17 | #define THIS_DS_STACK() Z_DS_STACK_P(getThis())
18 |
19 | #define ZVAL_DS_STACK(z, s) ZVAL_OBJ(z, php_ds_stack_create_object_ex(s))
20 |
21 | #define RETURN_DS_STACK(s) \
22 | do { \
23 | ds_stack_t *_s = s; \
24 | if (_s) { \
25 | ZVAL_DS_STACK(return_value, _s); \
26 | } else { \
27 | ZVAL_NULL(return_value); \
28 | } \
29 | return; \
30 | } while(0)
31 |
32 | zend_object *php_ds_stack_create_object_ex(ds_stack_t *stack);
33 | zend_object *php_ds_stack_create_object(zend_class_entry *ce);
34 | zend_object *php_ds_stack_create_clone(ds_stack_t *stack);
35 |
36 | PHP_DS_SERIALIZE_FUNCIONS(php_ds_stack);
37 |
38 | #endif
39 |
--------------------------------------------------------------------------------
/src/php/objects/php_queue.h:
--------------------------------------------------------------------------------
1 | #ifndef PHP_DS_QUEUE_H
2 | #define PHP_DS_QUEUE_H
3 |
4 | #include "../../ds/ds_queue.h"
5 |
6 | typedef struct _php_ds_queue_t {
7 | ds_queue_t *queue;
8 | zend_object std;
9 | } php_ds_queue_t;
10 |
11 | static inline php_ds_queue_t *php_ds_queue_fetch_object(zend_object *obj) {
12 | return (php_ds_queue_t *)((char*)(obj) - XtOffsetOf(php_ds_queue_t, std));
13 | }
14 |
15 | #define Z_DS_QUEUE(z) php_ds_queue_fetch_object(Z_OBJ(z))->queue
16 | #define Z_DS_QUEUE_P(z) Z_DS_QUEUE(*z)
17 | #define THIS_DS_QUEUE() Z_DS_QUEUE_P(getThis())
18 |
19 | #define ZVAL_DS_QUEUE(z, queue) \
20 | ZVAL_OBJ(z, php_ds_queue_create_object_ex(queue))
21 |
22 | #define RETURN_DS_QUEUE(q) \
23 | do { \
24 | ds_queue_t *_q = q; \
25 | if (_q) { \
26 | ZVAL_DS_QUEUE(return_value, _q); \
27 | } else { \
28 | ZVAL_NULL(return_value); \
29 | } \
30 | return; \
31 | } while(0)
32 |
33 | zend_object *php_ds_queue_create_object_ex(ds_queue_t *queue);
34 | zend_object *php_ds_queue_create_object(zend_class_entry *ce);
35 | zend_object *php_ds_queue_create_clone(ds_queue_t *queue);
36 |
37 | PHP_DS_SERIALIZE_FUNCIONS(php_ds_queue);
38 |
39 | #endif
40 |
--------------------------------------------------------------------------------
/src/php/objects/php_vector.h:
--------------------------------------------------------------------------------
1 | #ifndef PHP_DS_VECTOR_H
2 | #define PHP_DS_VECTOR_H
3 |
4 | #include "../../ds/ds_vector.h"
5 |
6 | typedef struct php_ds_vector {
7 | ds_vector_t *vector;
8 | zend_object std;
9 | } php_ds_vector_t;
10 |
11 | static inline php_ds_vector_t *php_ds_vector_fetch_object(zend_object *obj) {
12 | return (php_ds_vector_t *)((char*)(obj) - XtOffsetOf(php_ds_vector_t, std));
13 | }
14 |
15 | #define Z_DS_VECTOR(z) (php_ds_vector_fetch_object(Z_OBJ(z))->vector)
16 | #define Z_DS_VECTOR_P(z) Z_DS_VECTOR(*z)
17 | #define THIS_DS_VECTOR() Z_DS_VECTOR_P(getThis())
18 |
19 | #define ZVAL_DS_VECTOR(z, v) ZVAL_OBJ(z, php_ds_vector_create_object_ex(v))
20 |
21 | #define RETURN_DS_VECTOR(v) \
22 | do { \
23 | ds_vector_t *_v = v; \
24 | if (_v) { \
25 | ZVAL_DS_VECTOR(return_value, _v); \
26 | } else { \
27 | ZVAL_NULL(return_value); \
28 | } \
29 | return; \
30 | } while(0)
31 |
32 | zend_object *php_ds_vector_create_object_ex(ds_vector_t *vector);
33 | zend_object *php_ds_vector_create_object(zend_class_entry *ce);
34 | zend_object *php_ds_vector_create_clone(ds_vector_t *vector);
35 |
36 | PHP_DS_SERIALIZE_FUNCIONS(php_ds_vector);
37 |
38 | #endif
39 |
--------------------------------------------------------------------------------
/src/php/objects/php_map.h:
--------------------------------------------------------------------------------
1 | #ifndef PHP_DS_MAP_H
2 | #define PHP_DS_MAP_H
3 |
4 | #include "../../ds/ds_map.h"
5 |
6 | typedef struct _php_ds_map_t {
7 | ds_map_t *map;
8 | zend_object std;
9 | } php_ds_map_t;
10 |
11 | static inline php_ds_map_t *php_ds_map_fetch_object(zend_object *obj) {
12 | return (php_ds_map_t *)((char*)(obj) - XtOffsetOf(php_ds_map_t, std));
13 | }
14 |
15 | #define Z_DS_MAP(z) (php_ds_map_fetch_object(Z_OBJ(z))->map)
16 | #define Z_DS_MAP_P(z) Z_DS_MAP(*z)
17 | #define THIS_DS_MAP() Z_DS_MAP_P(getThis())
18 |
19 | #define ZVAL_DS_MAP(z, map) ZVAL_OBJ(z, php_ds_map_create_object_ex(map))
20 |
21 | #define RETURN_DS_MAP(m) \
22 | do { \
23 | ds_map_t *_m = m; \
24 | if (_m) { \
25 | ZVAL_DS_MAP(return_value, _m); \
26 | } else { \
27 | ZVAL_NULL(return_value); \
28 | } \
29 | return; \
30 | } while(0)
31 |
32 | zend_object *php_ds_map_create_object_ex(ds_map_t *map);
33 | zend_object *php_ds_map_create_object(zend_class_entry *ce);
34 | zend_object *php_ds_map_create_clone(ds_map_t *map);
35 |
36 | zval *ds_map_pairs(ds_map_t *map);
37 | HashTable *ds_map_pairs_to_php_hashtable(ds_map_t *map);
38 |
39 | PHP_DS_SERIALIZE_FUNCIONS(php_ds_map);
40 |
41 | #endif
42 |
--------------------------------------------------------------------------------
/src/php/objects/php_pair.h:
--------------------------------------------------------------------------------
1 | #ifndef PHP_DS_PAIR_H
2 | #define PHP_DS_PAIR_H
3 |
4 | #include "../../common.h"
5 |
6 | #define Z_DS_PAIR(z) ((php_ds_pair_t*)(Z_OBJ(z)))
7 | #define Z_DS_PAIR_P(z) Z_DS_PAIR(*z)
8 | #define THIS_DS_PAIR() Z_DS_PAIR_P(getThis())
9 |
10 | #define ZVAL_DS_PAIR(z, p) ZVAL_OBJ(z, (zend_object*) p)
11 |
12 | #define RETURN_DS_PAIR(p) \
13 | do { \
14 | php_ds_pair_t *_p = (php_ds_pair_t *) p; \
15 | if (_p) { \
16 | ZVAL_DS_PAIR(return_value, _p); \
17 | } else { \
18 | ZVAL_NULL(return_value); \
19 | } \
20 | return; \
21 | } while(0)
22 |
23 | typedef struct _php_ds_pair_t {
24 | zend_object std;
25 | } php_ds_pair_t;
26 |
27 | php_ds_pair_t *php_ds_pair_ex(zval *key, zval *value);
28 | php_ds_pair_t *php_ds_pair();
29 |
30 | void php_ds_pair_set_key(php_ds_pair_t *obj, zval *key);
31 | void php_ds_pair_set_value(php_ds_pair_t *obj, zval *value);
32 |
33 | zval *php_ds_pair_get_key(php_ds_pair_t *obj);
34 | zval *php_ds_pair_get_value(php_ds_pair_t *obj);
35 |
36 | zend_object *php_ds_pair_create_object(zend_class_entry *ce);
37 | zend_object *php_ds_pair_create_clone(php_ds_pair_t *obj);
38 |
39 | void php_ds_pair_to_array(php_ds_pair_t *obj, zval *result);
40 |
41 | PHP_DS_SERIALIZE_FUNCIONS(php_ds_pair);
42 |
43 | #endif
44 |
--------------------------------------------------------------------------------
/src/php/objects/php_deque.h:
--------------------------------------------------------------------------------
1 | #ifndef PHP_DS_DEQUE_H
2 | #define PHP_DS_DEQUE_H
3 |
4 | #include "../../ds/ds_deque.h"
5 |
6 | typedef struct php_ds_deque {
7 | ds_deque_t *deque;
8 | zend_object std;
9 | } php_ds_deque_t;
10 |
11 | static inline php_ds_deque_t *php_ds_deque_fetch_object(zend_object *obj) {
12 | return (php_ds_deque_t *)((char*)(obj) - XtOffsetOf(php_ds_deque_t, std));
13 | }
14 |
15 | #define Z_DS_DEQUE(z) (php_ds_deque_fetch_object(Z_OBJ(z))->deque)
16 | #define Z_DS_DEQUE_P(z) Z_DS_DEQUE(*z)
17 | #define THIS_DS_DEQUE() Z_DS_DEQUE_P(getThis())
18 |
19 | #define ZVAL_DS_DEQUE(z, d) ZVAL_OBJ(z, php_ds_deque_create_object_ex(d))
20 |
21 | #define RETURN_DS_DEQUE(d) \
22 | do { \
23 | ds_deque_t *_d = d; \
24 | if (_d) { \
25 | ZVAL_DS_DEQUE(return_value, _d); \
26 | } else { \
27 | ZVAL_NULL(return_value); \
28 | } \
29 | return; \
30 | } while(0)
31 |
32 |
33 | /**
34 | * Creates a new zend_object using an existing deque.
35 | */
36 | zend_object *php_ds_deque_create_object_ex(ds_deque_t *deque);
37 |
38 | /**
39 | * Creates a new deque zend_object.
40 | */
41 | zend_object *php_ds_deque_create_object(zend_class_entry *ce);
42 |
43 | /**
44 | * Creates an object clone of a deque.
45 | */
46 | zend_object *php_ds_deque_create_clone(ds_deque_t *deque);
47 |
48 | PHP_DS_SERIALIZE_FUNCIONS(php_ds_deque);
49 |
50 | #endif
51 |
--------------------------------------------------------------------------------
/src/php/classes/php_sequence_ce.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 |
3 | #include "php_collection_ce.h"
4 | #include "php_sequence_ce.h"
5 |
6 | zend_class_entry *sequence_ce;
7 |
8 | #define SEQUENCE_ABSTRACT_ME(name) PHP_ABSTRACT_ME(Sequence, name, arginfo_Sequence_##name)
9 |
10 | void php_ds_register_sequence()
11 | {
12 | zend_class_entry ce;
13 |
14 | zend_function_entry methods[] = {
15 | SEQUENCE_ABSTRACT_ME(allocate)
16 | SEQUENCE_ABSTRACT_ME(capacity)
17 | SEQUENCE_ABSTRACT_ME(contains)
18 | SEQUENCE_ABSTRACT_ME(filter)
19 | SEQUENCE_ABSTRACT_ME(find)
20 | SEQUENCE_ABSTRACT_ME(first)
21 | SEQUENCE_ABSTRACT_ME(get)
22 | SEQUENCE_ABSTRACT_ME(insert)
23 | SEQUENCE_ABSTRACT_ME(join)
24 | SEQUENCE_ABSTRACT_ME(last)
25 | SEQUENCE_ABSTRACT_ME(map)
26 | SEQUENCE_ABSTRACT_ME(merge)
27 | SEQUENCE_ABSTRACT_ME(pop)
28 | SEQUENCE_ABSTRACT_ME(push)
29 | SEQUENCE_ABSTRACT_ME(reduce)
30 | SEQUENCE_ABSTRACT_ME(remove)
31 | SEQUENCE_ABSTRACT_ME(reverse)
32 | SEQUENCE_ABSTRACT_ME(rotate)
33 | SEQUENCE_ABSTRACT_ME(set)
34 | SEQUENCE_ABSTRACT_ME(shift)
35 | SEQUENCE_ABSTRACT_ME(slice)
36 | SEQUENCE_ABSTRACT_ME(sort)
37 | SEQUENCE_ABSTRACT_ME(unshift)
38 | PHP_FE_END
39 | };
40 |
41 | INIT_CLASS_ENTRY(ce, PHP_DS_NS(Sequence), methods);
42 |
43 | sequence_ce = zend_register_internal_interface(&ce);
44 |
45 | zend_class_implements(sequence_ce, 2,
46 | collection_ce,
47 | zend_ce_arrayaccess
48 | );
49 | }
50 |
--------------------------------------------------------------------------------
/src/php/handlers/php_common_handlers.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 | #include "php_common_handlers.h"
3 | #include "zend_smart_str.h"
4 |
5 | int php_ds_default_cast_object
6 | #if PHP_VERSION_ID >= 80000
7 | (zend_object *obj, zval *return_value, int type) {
8 | zend_class_entry *ce = obj->ce;
9 | #else
10 | (zval *obj, zval *return_value, int type) {
11 | zend_class_entry *ce = Z_OBJCE_P(obj);
12 | #endif
13 | switch (type) {
14 | case IS_STRING: {
15 | smart_str buffer = {0};
16 |
17 | smart_str_appendl(&buffer, "object(", 7);
18 | smart_str_append (&buffer, ce->name);
19 | smart_str_appendc(&buffer, ')');
20 |
21 | smart_str_0(&buffer);
22 | ZVAL_STR(return_value, buffer.s);
23 | return SUCCESS;
24 | }
25 | case _IS_BOOL: {
26 | ZVAL_TRUE(return_value);
27 | return SUCCESS;
28 | }
29 | }
30 |
31 | return FAILURE;
32 | }
33 |
34 | zval *php_ds_read_dimension_by_key_not_supported
35 | #if PHP_VERSION_ID >= 80000
36 | (zend_object *obj, zval *offset, int type, zval *rv) {
37 | #else
38 | (zval *obj, zval *offset, int type, zval *rv) {
39 | #endif
40 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
41 | return NULL;
42 | }
43 |
44 | int php_ds_has_dimension_by_key_not_supported
45 | #if PHP_VERSION_ID >= 80000
46 | (zend_object *obj, zval *offset, int check_empty) {
47 | #else
48 | (zval *obj, zval *offset, int check_empty) {
49 | #endif
50 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
51 | return 0;
52 | }
53 |
54 | void php_ds_unset_dimension_by_key_not_supported
55 | #if PHP_VERSION_ID >= 80000
56 | (zend_object *obj, zval *offset) {
57 | #else
58 | (zval *obj, zval *offset) {
59 | #endif
60 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
61 | }
62 |
--------------------------------------------------------------------------------
/src/php/objects/php_priority_queue.h:
--------------------------------------------------------------------------------
1 | #ifndef PHP_DS_PRIORITY_QUEUE_H
2 | #define PHP_DS_PRIORITY_QUEUE_H
3 |
4 | #include "../../ds/ds_priority_queue.h"
5 |
6 | typedef struct _php_ds_priority_queue_t {
7 | ds_priority_queue_t *queue;
8 | zval *gc_data;
9 | int gc_size;
10 | zend_object std;
11 | } php_ds_priority_queue_t;
12 |
13 | static inline php_ds_priority_queue_t *php_ds_priority_queue_fetch_object(zend_object *obj) {
14 | return (php_ds_priority_queue_t *)((char*)(obj) - XtOffsetOf(php_ds_priority_queue_t, std));
15 | }
16 |
17 | #define Z_DS_PRIORITY_QUEUE(z) (php_ds_priority_queue_fetch_object(Z_OBJ(z))->queue)
18 | #define Z_DS_PRIORITY_QUEUE_P(z) Z_DS_PRIORITY_QUEUE(*z)
19 | #define THIS_DS_PRIORITY_QUEUE() Z_DS_PRIORITY_QUEUE_P(getThis())
20 |
21 | #define ZVAL_DS_PRIORITY_QUEUE(z, queue) \
22 | ZVAL_OBJ(z, (php_ds_priority_queue_create_object_ex(queue)))
23 |
24 | #define RETURN_DS_PRIORITY_QUEUE(queue) \
25 | do { \
26 | ds_priority_queue_t *_queue = queue; \
27 | if (_queue) { \
28 | ZVAL_DS_PRIORITY_QUEUE(return_value, _queue); \
29 | } else { \
30 | ZVAL_NULL(return_value); \
31 | } \
32 | return; \
33 | } while(0)
34 |
35 | zend_object *php_ds_priority_queue_create_object_ex(ds_priority_queue_t *queue);
36 | zend_object *php_ds_priority_queue_create_object(zend_class_entry *ce);
37 | zend_object *php_ds_priority_queue_create_clone(ds_priority_queue_t *queue);
38 |
39 | PHP_DS_SERIALIZE_FUNCIONS(php_ds_priority_queue);
40 |
41 | #endif
42 |
--------------------------------------------------------------------------------
/src/ds/ds_queue.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_QUEUE_H
2 | #define DS_QUEUE_H
3 |
4 | #include "../common.h"
5 | #include "ds_deque.h"
6 |
7 | #define QUEUE_SIZE(q) ((q)->deque->size)
8 | #define QUEUE_IS_EMPTY(q) ((q)->deque->size == 0)
9 |
10 | #define QUEUE_FOREACH(queue, value) \
11 | do { \
12 | zval _tmp; \
13 | while ( ! DS_DEQUE_IS_EMPTY(queue->deque)) { \
14 | ds_deque_shift(queue->deque, &_tmp); \
15 | value = &_tmp;
16 |
17 | #define QUEUE_FOREACH_END() \
18 | } \
19 | zval_ptr_dtor(&_tmp); \
20 | } while (0) \
21 |
22 | typedef struct _ds_queue_t {
23 | ds_deque_t *deque;
24 | } ds_queue_t;
25 |
26 | ds_queue_t *ds_queue_ex(ds_deque_t *deque);
27 | ds_queue_t *ds_queue();
28 | ds_queue_t *ds_queue_clone(ds_queue_t *queue);
29 |
30 | void ds_queue_allocate(ds_queue_t *queue, zend_long capacity);
31 | zend_long ds_queue_capacity(ds_queue_t *queue);
32 |
33 | void ds_queue_push(ds_queue_t *queue, VA_PARAMS);
34 | void ds_queue_push_one(ds_queue_t *queue, zval *value);
35 | void ds_queue_clear(ds_queue_t *queue);
36 | void ds_queue_pop(ds_queue_t *queue, zval *return_value);
37 | void ds_queue_pop_throw(ds_queue_t *queue, zval *return_value);
38 | zval *ds_queue_peek(ds_queue_t *queue);
39 | zval *ds_queue_peek_throw(ds_queue_t *queue);
40 | void ds_queue_push_all(ds_queue_t *queue, zval *value);
41 | void ds_queue_to_array(ds_queue_t *queue, zval *return_value);
42 | void ds_queue_free(ds_queue_t *queue);
43 |
44 | int ds_queue_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data);
45 | int ds_queue_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data);
46 |
47 | #endif
48 |
--------------------------------------------------------------------------------
/src/php/handlers/php_pair_handlers.c:
--------------------------------------------------------------------------------
1 | #include "php_pair_handlers.h"
2 | #include "php_common_handlers.h"
3 | #include "../objects/php_pair.h"
4 |
5 | zend_object_handlers php_pair_handlers;
6 |
7 | static void php_ds_pair_unset_property
8 | #if PHP_VERSION_ID >= 80000
9 | (zend_object *obj, zend_string *offset, void **cache_slot) {
10 | if (zend_string_equals_literal(offset, "key") || zend_string_equals_literal(offset, "value")) {
11 | zend_update_property_null(obj->ce, obj, ZSTR_VAL(offset), ZSTR_LEN(offset));
12 | }
13 | #else
14 | (zval *obj, zval *offset, void **cache_slot) {
15 | if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) {
16 | if (ZVAL_EQUALS_STRING(offset, "key") || ZVAL_EQUALS_STRING(offset, "value")) {
17 | zend_update_property_null(Z_OBJCE_P(obj), obj, Z_STRVAL_P(offset), Z_STRLEN_P(offset));
18 | }
19 | }
20 | #endif
21 | }
22 |
23 | static int php_ds_pair_count_elements
24 | #if PHP_VERSION_ID >= 80000
25 | (zend_object *obj, zend_long *count) {
26 | #else
27 | (zval *obj, zend_long *count) {
28 | #endif
29 | *count = 2;
30 | return SUCCESS;
31 | }
32 |
33 | static zend_object *php_ds_pair_clone_object
34 | #if PHP_VERSION_ID >= 80000
35 | (zend_object *obj) {
36 | return php_ds_pair_create_clone((php_ds_pair_t*)obj);
37 | #else
38 | (zval *obj) {
39 | return php_ds_pair_create_clone(Z_DS_PAIR_P(obj));
40 | #endif
41 | }
42 |
43 | void php_ds_register_pair_handlers()
44 | {
45 | memcpy(&php_pair_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
46 |
47 | php_pair_handlers.offset = XtOffsetOf(php_ds_pair_t, std);
48 |
49 | php_pair_handlers.clone_obj = php_ds_pair_clone_object;
50 | php_pair_handlers.cast_object = php_ds_default_cast_object;
51 | php_pair_handlers.count_elements = php_ds_pair_count_elements;
52 | php_pair_handlers.unset_property = php_ds_pair_unset_property;
53 | }
54 |
--------------------------------------------------------------------------------
/src/ds/ds_stack.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_STACK_H
2 | #define DS_STACK_H
3 |
4 | #include "../common.h"
5 | #include "ds_vector.h"
6 |
7 | #define DS_STACK_SIZE(s) ((s)->vector->size)
8 | #define DS_STACK_CAPACITY(s) ((s)->vector->capacity)
9 | #define DS_STACK_IS_EMPTY(s) (DS_STACK_SIZE(s) == 0)
10 |
11 | #define DS_STACK_FOREACH(stack, value) \
12 | do { \
13 | zval _tmp; \
14 | \
15 | ds_vector_t *_v = stack->vector; \
16 | zval *_end = _v->buffer; \
17 | zval *_pos = _end + _v->size - 1; \
18 | \
19 | for (; _pos >= _end; --_pos, --_v->size) { \
20 | ZVAL_COPY(&_tmp, _pos); \
21 | zval_ptr_dtor(_pos); \
22 | value = &_tmp;
23 |
24 | #define DS_STACK_FOREACH_END() \
25 | } \
26 | zval_ptr_dtor(&_tmp); \
27 | } while (0) \
28 |
29 | typedef struct _ds_stack_t {
30 | ds_vector_t *vector;
31 | } ds_stack_t;
32 |
33 | ds_stack_t *ds_stack();
34 | ds_stack_t *ds_stack_ex(ds_vector_t *vector);
35 | ds_stack_t *ds_stack_clone(ds_stack_t *stack);
36 |
37 | void ds_stack_push(ds_stack_t *stack, zval *value);
38 | void ds_stack_push_va(ds_stack_t *stack, VA_PARAMS);
39 | void ds_stack_allocate(ds_stack_t *stack, zend_long capacity);
40 | void ds_stack_clear(ds_stack_t *stack);
41 | void ds_stack_pop(ds_stack_t *stack, zval *return_value);
42 | void ds_stack_pop_throw(ds_stack_t *stack, zval *return_value);
43 | zval *ds_stack_peek(ds_stack_t *stack);
44 | zval *ds_stack_peek_throw(ds_stack_t *stack);
45 | void ds_stack_push_all(ds_stack_t *stack, zval *value);
46 | void ds_stack_to_array(ds_stack_t *stack, zval *return_value);
47 | void ds_stack_free(ds_stack_t *stack);
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/src/php/classes/php_pair_ce.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 | #include "../parameters.h"
3 | #include "../arginfo.h"
4 | #include "../objects/php_pair.h"
5 | #include "../handlers/php_pair_handlers.h"
6 | #include "php_pair_ce.h"
7 |
8 | #define METHOD(name) PHP_METHOD(Pair, name)
9 |
10 | zend_class_entry *php_ds_pair_ce;
11 |
12 | METHOD(__construct)
13 | {
14 | PARSE_OPTIONAL_ZVAL_OPTIONAL_ZVAL(key, value);
15 | {
16 | php_ds_pair_t *pair = THIS_DS_PAIR();
17 |
18 | if (key) {
19 | php_ds_pair_set_key(pair, key);
20 | }
21 |
22 | if (value) {
23 | php_ds_pair_set_value(pair, value);
24 | }
25 | }
26 | }
27 |
28 | METHOD(copy)
29 | {
30 | PARSE_NONE;
31 | RETURN_DS_PAIR(php_ds_pair_create_clone(THIS_DS_PAIR()));
32 | }
33 |
34 | METHOD(toArray)
35 | {
36 | PARSE_NONE;
37 | php_ds_pair_to_array(THIS_DS_PAIR(), return_value);
38 | }
39 |
40 | METHOD(jsonSerialize)
41 | {
42 | PARSE_NONE;
43 | php_ds_pair_to_array(THIS_DS_PAIR(), return_value);
44 | }
45 |
46 | void php_ds_register_pair()
47 | {
48 | zend_class_entry ce;
49 |
50 | zend_function_entry methods[] = {
51 | PHP_DS_ME(Pair, __construct)
52 | PHP_DS_ME(Pair, copy)
53 | PHP_DS_ME(Pair, jsonSerialize)
54 | PHP_DS_ME(Pair, toArray)
55 | PHP_FE_END
56 | };
57 |
58 | INIT_CLASS_ENTRY(ce, PHP_DS_NS(Pair), methods);
59 | php_ds_pair_ce = zend_register_internal_class(&ce);
60 |
61 | php_ds_pair_ce->ce_flags |= ZEND_ACC_FINAL;
62 | php_ds_pair_ce->create_object = php_ds_pair_create_object;
63 | php_ds_pair_ce->serialize = php_ds_pair_serialize;
64 | php_ds_pair_ce->unserialize = php_ds_pair_unserialize;
65 |
66 | zend_declare_property_null(php_ds_pair_ce, STR_AND_LEN("key"), ZEND_ACC_PUBLIC);
67 | zend_declare_property_null(php_ds_pair_ce, STR_AND_LEN("value"), ZEND_ACC_PUBLIC);
68 |
69 | zend_class_implements(php_ds_pair_ce, 1, php_json_serializable_ce);
70 | php_ds_register_pair_handlers();
71 | }
72 |
--------------------------------------------------------------------------------
/src/php/classes/php_set_ce.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_SET_CE_H
2 | #define DS_SET_CE_H
3 |
4 | #include "php.h"
5 | #include "../../common.h"
6 | #include "../arginfo.h"
7 |
8 | extern zend_class_entry *php_ds_set_ce;
9 |
10 | ARGINFO_OPTIONAL_ZVAL( Set___construct, values);
11 | ARGINFO_OPTIONAL_STRING( Set_join, glue);
12 | ARGINFO_LONG( Set_allocate, capacity);
13 | ARGINFO_NONE_RETURN_LONG( Set_capacity);
14 | ARGINFO_VARIADIC_ZVAL( Set_add, values);
15 | ARGINFO_VARIADIC_ZVAL( Set_remove, values);
16 | ARGINFO_LONG( Set_get, index);
17 | ARGINFO_VARIADIC_ZVAL_RETURN_BOOL( Set_contains, values);
18 | ARGINFO_DS_RETURN_DS( Set_diff, set, Set, Set);
19 | ARGINFO_DS_RETURN_DS( Set_intersect, set, Set, Set);
20 | ARGINFO_DS_RETURN_DS( Set_xor, set, Set, Set);
21 | ARGINFO_NONE( Set_first);
22 | ARGINFO_NONE( Set_last);
23 | ARGINFO_ZVAL_RETURN_DS( Set_merge, values, Set);
24 | ARGINFO_DS_RETURN_DS( Set_union, set, Set, Set);
25 | ARGINFO_OPTIONAL_CALLABLE( Set_sort, comparator);
26 | ARGINFO_OPTIONAL_CALLABLE_RETURN_DS( Set_sorted, comparator, Set);
27 | ARGINFO_CALLABLE_OPTIONAL_ZVAL( Set_reduce, callback, initial);
28 | ARGINFO_LONG_OPTIONAL_LONG_RETURN_DS( Set_slice, index, length, Set);
29 | ARGINFO_OPTIONAL_CALLABLE_RETURN_DS( Set_filter, predicate, Set);
30 | ARGINFO_CALLABLE_RETURN_DS( Set_map, callback, Set);
31 | ARGINFO_NONE( Set_reverse);
32 | ARGINFO_NONE_RETURN_DS( Set_reversed, Set);
33 | ARGINFO_NONE( Set_sum);
34 | ARGINFO_NONE_RETURN_OBJ( Set_getIterator, Traversable);
35 |
36 | ARGINFO_ZVAL_RETURN_BOOL( Set_offsetExists, offset);
37 | ARGINFO_OFFSET_GET( Set_offsetGet);
38 | ARGINFO_OFFSET_SET( Set_offsetSet);
39 | ARGINFO_OFFSET_UNSET( Set_offsetUnset);
40 |
41 | void php_ds_register_set();
42 |
43 | #endif
44 |
--------------------------------------------------------------------------------
/src/ds/ds_stack.c:
--------------------------------------------------------------------------------
1 | #include "../common.h"
2 |
3 | #include "../php/iterators/php_stack_iterator.h"
4 | #include "../php/handlers/php_stack_handlers.h"
5 | #include "../php/classes/php_stack_ce.h"
6 |
7 | #include "ds_stack.h"
8 |
9 | ds_stack_t *ds_stack_ex(ds_vector_t *vector)
10 | {
11 | ds_stack_t *stack = ecalloc(1, sizeof(ds_stack_t));
12 | stack->vector = vector;
13 | return stack;
14 | }
15 |
16 | ds_stack_t *ds_stack()
17 | {
18 | return ds_stack_ex(ds_vector());
19 | }
20 |
21 | ds_stack_t *ds_stack_clone(ds_stack_t *stack)
22 | {
23 | return ds_stack_ex(ds_vector_clone(stack->vector));
24 | }
25 |
26 | void ds_stack_free(ds_stack_t *stack)
27 | {
28 | ds_vector_free(stack->vector);
29 | efree(stack);
30 | }
31 |
32 | void ds_stack_allocate(ds_stack_t *stack, zend_long capacity)
33 | {
34 | ds_vector_allocate(stack->vector, capacity);
35 | }
36 |
37 | void ds_stack_push_va(ds_stack_t *stack, VA_PARAMS)
38 | {
39 | ds_vector_push_va(stack->vector, argc, argv);
40 | }
41 |
42 | void ds_stack_push(ds_stack_t *stack, zval *value)
43 | {
44 | ds_vector_push(stack->vector, value);
45 | }
46 |
47 | void ds_stack_clear(ds_stack_t *stack)
48 | {
49 | ds_vector_clear(stack->vector);
50 | }
51 |
52 | void ds_stack_push_all(ds_stack_t *stack, zval *value)
53 | {
54 | ds_vector_push_all(stack->vector, value);
55 | }
56 |
57 | void ds_stack_to_array(ds_stack_t *stack, zval *return_value)
58 | {
59 | zend_long size = DS_STACK_SIZE(stack);
60 |
61 | if (size == 0) {
62 | array_init(return_value);
63 |
64 | } else {
65 | zval *value;
66 | array_init_size(return_value, size);
67 |
68 | DS_VECTOR_FOREACH_REVERSED(stack->vector, value) {
69 | add_next_index_zval(return_value, value);
70 | Z_TRY_ADDREF_P(value);
71 | }
72 | DS_VECTOR_FOREACH_END();
73 | }
74 | }
75 |
76 | void ds_stack_pop_throw(ds_stack_t *stack, zval *return_value)
77 | {
78 | ds_vector_pop_throw(stack->vector, return_value);
79 | }
80 |
81 | void ds_stack_pop(ds_stack_t *stack, zval *return_value)
82 | {
83 | ds_vector_pop(stack->vector, return_value);
84 | }
85 |
86 | zval *ds_stack_peek(ds_stack_t *stack)
87 | {
88 | return ds_vector_get_last(stack->vector);
89 | }
90 |
91 | zval *ds_stack_peek_throw(ds_stack_t *stack)
92 | {
93 | return ds_vector_get_last_throw(stack->vector);
94 | }
95 |
--------------------------------------------------------------------------------
/src/php/objects/php_map.c:
--------------------------------------------------------------------------------
1 | #include "../handlers/php_map_handlers.h"
2 | #include "../classes/php_map_ce.h"
3 |
4 | #include "php_map.h"
5 | #include "php_pair.h"
6 |
7 | zend_object *php_ds_map_create_object_ex(ds_map_t *map)
8 | {
9 | #if PHP_VERSION_ID < 70300
10 | php_ds_map_t *obj = ecalloc(1, sizeof(php_ds_map_t) + zend_object_properties_size(php_ds_map_ce));
11 | #else
12 | php_ds_map_t *obj = zend_object_alloc(sizeof(php_ds_map_t), php_ds_map_ce);
13 | #endif
14 | zend_object_std_init(&obj->std, php_ds_map_ce);
15 | obj->std.handlers = &php_map_handlers;
16 | obj->map = map;
17 | return &obj->std;
18 | }
19 |
20 | zend_object *php_ds_map_create_object(zend_class_entry *ce)
21 | {
22 | return php_ds_map_create_object_ex(ds_map());
23 | }
24 |
25 | zend_object *php_ds_map_create_clone(ds_map_t *map)
26 | {
27 | return php_ds_map_create_object_ex(ds_map_clone(map));
28 | }
29 |
30 | HashTable *ds_map_pairs_to_php_hashtable(ds_map_t *map)
31 | {
32 | HashTable *array;
33 |
34 | zval *key;
35 | zval *value;
36 |
37 | zval pair;
38 |
39 | ALLOC_HASHTABLE(array);
40 | zend_hash_init(array, DS_MAP_SIZE(map), NULL, ZVAL_PTR_DTOR, 0);
41 |
42 | DS_HTABLE_FOREACH_KEY_VALUE(map->table, key, value) {
43 | ZVAL_DS_PAIR(&pair, php_ds_pair_ex(key, value));
44 | zend_hash_next_index_insert(array, &pair);
45 | }
46 | DS_HTABLE_FOREACH_END();
47 |
48 | return array;
49 | }
50 |
51 | zval *ds_map_pairs(ds_map_t *map)
52 | {
53 | zval *buffer = ds_allocate_zval_buffer(DS_MAP_SIZE(map));
54 | zval *target = buffer;
55 |
56 | zval *key;
57 | zval *value;
58 |
59 | DS_HTABLE_FOREACH_KEY_VALUE(map->table, key, value) {
60 | ZVAL_DS_PAIR(target++, php_ds_pair_ex(key, value));
61 | }
62 | DS_HTABLE_FOREACH_END();
63 |
64 | return buffer;
65 | }
66 |
67 | int php_ds_map_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data)
68 | {
69 | return ds_htable_serialize(Z_DS_MAP_P(object)->table, buffer, length, data);
70 | }
71 |
72 | int php_ds_map_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data)
73 | {
74 | ds_map_t *map = ds_map();
75 |
76 | if (ds_htable_unserialize(map->table, buffer, length, data) == FAILURE) {
77 | ds_map_free(map);
78 | return FAILURE;
79 | }
80 |
81 | ZVAL_DS_MAP(object, map);
82 | return SUCCESS;
83 | }
84 |
--------------------------------------------------------------------------------
/src/ds/ds_queue.c:
--------------------------------------------------------------------------------
1 | #include "../common.h"
2 |
3 | #include "../php/iterators/php_queue_iterator.h"
4 | #include "../php/handlers/php_queue_handlers.h"
5 | #include "../php/classes/php_queue_ce.h"
6 |
7 | #include "ds_deque.h"
8 | #include "ds_queue.h"
9 |
10 | ds_queue_t *ds_queue_ex(ds_deque_t *deque)
11 | {
12 | ds_queue_t *queue = ecalloc(1, sizeof(ds_queue_t));
13 | queue->deque = deque;
14 | return queue;
15 | }
16 |
17 | ds_queue_t *ds_queue()
18 | {
19 | return ds_queue_ex(ds_deque());
20 | }
21 |
22 | ds_queue_t *ds_queue_clone(ds_queue_t *queue)
23 | {
24 | return ds_queue_ex(ds_deque_clone(queue->deque));
25 | }
26 |
27 | void ds_queue_free(ds_queue_t *queue)
28 | {
29 | ds_deque_free(queue->deque);
30 | efree(queue);
31 | }
32 |
33 | void ds_queue_allocate(ds_queue_t *queue, zend_long capacity)
34 | {
35 | ds_deque_allocate(queue->deque, capacity);
36 | }
37 |
38 | zend_long ds_queue_capacity(ds_queue_t *queue)
39 | {
40 | return queue->deque->capacity;
41 | }
42 |
43 | void ds_queue_push(ds_queue_t *queue, VA_PARAMS)
44 | {
45 | ds_deque_push_va(queue->deque, argc, argv);
46 | }
47 |
48 | void ds_queue_push_one(ds_queue_t *queue, zval *value)
49 | {
50 | ds_deque_push(queue->deque, value);
51 | }
52 |
53 | void ds_queue_clear(ds_queue_t *queue)
54 | {
55 | ds_deque_clear(queue->deque);
56 | }
57 |
58 | void ds_queue_push_all(ds_queue_t *queue, zval *value)
59 | {
60 | ds_deque_push_all(queue->deque, value);
61 | }
62 |
63 | void ds_queue_to_array(ds_queue_t *queue, zval *return_value)
64 | {
65 | zend_long size = QUEUE_SIZE(queue);
66 |
67 | if (size == 0) {
68 | array_init(return_value);
69 |
70 | } else {
71 | zval *value;
72 | array_init_size(return_value, size);
73 |
74 | DS_DEQUE_FOREACH(queue->deque, value) {
75 | add_next_index_zval(return_value, value);
76 | Z_TRY_ADDREF_P(value);
77 | }
78 | DS_DEQUE_FOREACH_END();
79 | }
80 | }
81 |
82 | void ds_queue_pop_throw(ds_queue_t *queue, zval *return_value)
83 | {
84 | ds_deque_shift_throw(queue->deque, return_value);
85 | }
86 |
87 | void ds_queue_pop(ds_queue_t *queue, zval *return_value)
88 | {
89 | ds_deque_shift(queue->deque, return_value);
90 | }
91 |
92 | zval *ds_queue_peek_throw(ds_queue_t *queue)
93 | {
94 | return ds_deque_get_first_throw(queue->deque);
95 | }
96 |
97 | zval *ds_queue_peek(ds_queue_t *queue)
98 | {
99 | return ds_deque_get_first(queue->deque);
100 | }
101 |
--------------------------------------------------------------------------------
/src/ds/ds_set.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_SET_H
2 | #define DS_SET_H
3 |
4 | #include "../common.h"
5 | #include "ds_htable.h"
6 |
7 | #define DS_SET_SIZE(s) ((s)->table->size)
8 | #define DS_SET_CAPACITY(s) ((s)->table->capacity)
9 | #define DS_SET_IS_EMPTY(s) (DS_SET_SIZE(s) == 0)
10 |
11 | #define DS_SET_FOREACH(set, value) DS_HTABLE_FOREACH_KEY(set->table, value)
12 | #define DS_SET_FOREACH_END() DS_HTABLE_FOREACH_END()
13 |
14 | typedef struct _ds_set_t {
15 | ds_htable_t *table;
16 | } ds_set_t;
17 |
18 | ds_set_t *ds_set();
19 | ds_set_t *ds_set_ex(ds_htable_t *table);
20 | ds_set_t *ds_set_clone(ds_set_t *set);
21 |
22 | void ds_set_free(ds_set_t *set);
23 | void ds_set_clear(ds_set_t *set);
24 | void ds_set_allocate(ds_set_t *set, zend_long capacity);
25 |
26 | void ds_set_add(ds_set_t *set, zval *value);
27 | void ds_set_add_va(ds_set_t *set, VA_PARAMS);
28 | bool ds_set_contains_va(ds_set_t *set, VA_PARAMS);
29 | bool ds_set_contains(ds_set_t *set, zval *value);
30 | void ds_set_remove_va(ds_set_t *set, VA_PARAMS);
31 |
32 | void ds_set_to_array(ds_set_t *set, zval *arr);
33 | void ds_set_add_all(ds_set_t *set, zval *value);
34 |
35 | zval *ds_set_get(ds_set_t *set, zend_long index);
36 | zval *ds_set_get_first(ds_set_t *set);
37 | zval *ds_set_get_last(ds_set_t *set);
38 |
39 | ds_set_t *ds_set_slice(ds_set_t *set, zend_long index, zend_long length);
40 |
41 | void ds_set_sort_callback(ds_set_t *set);
42 | void ds_set_sort(ds_set_t *set);
43 |
44 | ds_set_t *ds_set_sorted_callback(ds_set_t *set);
45 | ds_set_t *ds_set_sorted(ds_set_t *set);
46 |
47 | void ds_set_join (ds_set_t *set, const char *glue, const size_t len, zval *return_value);
48 | void ds_set_reduce(ds_set_t *set, FCI_PARAMS, zval *initial, zval *return_value);
49 |
50 | ds_set_t *ds_set_map(ds_set_t *set, FCI_PARAMS);
51 | ds_set_t *ds_set_filter_callback(ds_set_t *set, FCI_PARAMS);
52 | ds_set_t *ds_set_filter(ds_set_t *set);
53 |
54 | void ds_set_reverse (ds_set_t *set);
55 | ds_set_t *ds_set_reversed(ds_set_t *set);
56 |
57 | ds_set_t *ds_set_diff(ds_set_t *set, ds_set_t *other);
58 | ds_set_t *ds_set_intersect(ds_set_t *set, ds_set_t *other);
59 | ds_set_t *ds_set_xor(ds_set_t *set, ds_set_t *other);
60 | ds_set_t *ds_set_union(ds_set_t *set, ds_set_t *other);
61 | ds_set_t *ds_set_merge(ds_set_t *set, zval *values);
62 |
63 | void ds_set_assign_diff(ds_set_t *set, ds_set_t *other);
64 | void ds_set_assign_intersect(ds_set_t *set, ds_set_t *other);
65 | void ds_set_assign_xor(ds_set_t *set, ds_set_t *other);
66 | void ds_set_assign_union(ds_set_t *set, ds_set_t *other);
67 |
68 | void ds_set_sum(ds_set_t *set, zval *return_value);
69 |
70 | #endif
71 |
--------------------------------------------------------------------------------
/src/ds/ds_map.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_MAP_H
2 | #define DS_MAP_H
3 |
4 | #include "../common.h"
5 | #include "ds_htable.h"
6 | #include "../php/objects/php_pair.h"
7 |
8 | typedef struct _ds_map_t {
9 | ds_htable_t *table;
10 | } ds_map_t;
11 |
12 | #define DS_MAP_SIZE(m) ((m)->table->size)
13 | #define DS_MAP_IS_EMPTY(m) (DS_MAP_SIZE(m) == 0)
14 |
15 | ds_map_t *ds_map();
16 | ds_map_t *ds_map_clone(ds_map_t *map);
17 |
18 | void ds_map_clear(ds_map_t *map);
19 | void ds_map_free(ds_map_t *map);
20 |
21 | void ds_map_reverse(ds_map_t *map);
22 | ds_map_t *ds_map_reversed(ds_map_t *map);
23 |
24 | zval *ds_map_get(ds_map_t *map, zval *key, zval *def);
25 | void ds_map_put(ds_map_t *map, zval *key, zval *value);
26 | void ds_map_remove(ds_map_t *map, zval *key, zval *def, zval *return_value);
27 |
28 | bool ds_map_has_key(ds_map_t *map, zval *key);
29 | bool ds_map_has_value(ds_map_t *map, zval *value);
30 |
31 | bool ds_map_has_keys(ds_map_t *map, VA_PARAMS);
32 | bool ds_map_has_values(ds_map_t *map, VA_PARAMS);
33 |
34 |
35 | void ds_map_to_array(ds_map_t *map, zval *return_value);
36 | void ds_map_put_all(ds_map_t *map, zval *values);
37 |
38 | ds_map_t *ds_map_slice(ds_map_t *map, zend_long index, zend_long length);
39 |
40 | zval *ds_map_values(ds_map_t *map);
41 |
42 | ds_map_t *ds_map_map(ds_map_t *map, FCI_PARAMS);
43 | ds_map_t *ds_map_filter(ds_map_t *map);
44 | ds_map_t *ds_map_filter_callback(ds_map_t *map, FCI_PARAMS);
45 |
46 | void ds_map_allocate(ds_map_t *map, zend_long capacity);
47 | zend_long ds_map_capacity(ds_map_t *map);
48 |
49 | void ds_map_sort_by_value_callback(ds_map_t *map);
50 | void ds_map_sort_by_value(ds_map_t *map);
51 | void ds_map_sort_by_key_callback(ds_map_t *map);
52 | void ds_map_sort_by_key(ds_map_t *map);
53 |
54 | ds_map_t *ds_map_sorted_by_value_callback(ds_map_t *map);
55 | ds_map_t *ds_map_sorted_by_value(ds_map_t *map);
56 | ds_map_t *ds_map_sorted_by_key_callback(ds_map_t *map);
57 | ds_map_t *ds_map_sorted_by_key(ds_map_t *map);
58 |
59 | ds_map_t *ds_map_merge(ds_map_t *map, zval *values);
60 | ds_map_t *ds_map_xor(ds_map_t *map, ds_map_t *other);
61 | ds_map_t *ds_map_diff(ds_map_t *map, ds_map_t *other);
62 | ds_map_t *ds_map_intersect(ds_map_t *map, ds_map_t *other);
63 | ds_map_t *ds_map_union(ds_map_t *map, ds_map_t *other);
64 |
65 | php_ds_pair_t *ds_map_first(ds_map_t *map);
66 | php_ds_pair_t *ds_map_last(ds_map_t *map);
67 | php_ds_pair_t *ds_map_skip(ds_map_t *map, zend_long position);
68 |
69 | void ds_map_sum(ds_map_t *map, zval *return_value);
70 | void ds_map_reduce(ds_map_t *map, FCI_PARAMS, zval *initial, zval *return_value);
71 | void ds_map_apply(ds_map_t *map, FCI_PARAMS);
72 |
73 |
74 | #endif
75 |
--------------------------------------------------------------------------------
/php_ds.c:
--------------------------------------------------------------------------------
1 | #ifdef HAVE_CONFIG_H
2 | #include "config.h"
3 | #endif
4 |
5 | #include "php.h"
6 | #include "main/php.h"
7 | #include "ext/standard/info.h"
8 | #include "ext/standard/php_var.h"
9 | #include "php_ds.h"
10 |
11 | #include "src/php/classes/php_hashable_ce.h"
12 | #include "src/php/classes/php_collection_ce.h"
13 | #include "src/php/classes/php_sequence_ce.h"
14 | #include "src/php/classes/php_vector_ce.h"
15 | #include "src/php/classes/php_deque_ce.h"
16 | #include "src/php/classes/php_set_ce.h"
17 | #include "src/php/classes/php_map_ce.h"
18 | #include "src/php/classes/php_stack_ce.h"
19 | #include "src/php/classes/php_pair_ce.h"
20 | #include "src/php/classes/php_priority_queue_ce.h"
21 | #include "src/php/classes/php_queue_ce.h"
22 |
23 | ZEND_DECLARE_MODULE_GLOBALS(ds);
24 |
25 | static inline void php_ds_init_globals(zend_ds_globals *dsg) {
26 | memset(dsg, 0, sizeof(zend_ds_globals));
27 | }
28 |
29 | PHP_MINIT_FUNCTION(ds)
30 | {
31 | ZEND_INIT_MODULE_GLOBALS(ds, php_ds_init_globals, NULL);
32 |
33 | // Interfaces
34 | php_ds_register_hashable();
35 | php_ds_register_collection();
36 | php_ds_register_sequence();
37 |
38 | // Classes
39 | php_ds_register_vector();
40 | php_ds_register_deque();
41 | php_ds_register_stack();
42 | php_ds_register_queue();
43 | php_ds_register_map();
44 | php_ds_register_set();
45 | php_ds_register_priority_queue();
46 | php_ds_register_pair();
47 |
48 | return SUCCESS;
49 | }
50 |
51 | PHP_RINIT_FUNCTION(ds)
52 | {
53 | #if defined(COMPILE_DL_DS) && defined(ZTS)
54 | ZEND_TSRMLS_CACHE_UPDATE();
55 | #endif
56 |
57 | return SUCCESS;
58 | }
59 |
60 | PHP_RSHUTDOWN_FUNCTION(ds)
61 | {
62 | return SUCCESS;
63 | }
64 |
65 | PHP_MINFO_FUNCTION(ds)
66 | {
67 | php_info_print_table_start();
68 | php_info_print_table_row(2, "ds support", "enabled");
69 | php_info_print_table_row(2, "ds version", PHP_DS_VERSION);
70 | php_info_print_table_end();
71 | }
72 |
73 | static const zend_module_dep ds_deps[] = {
74 | ZEND_MOD_REQUIRED("json")
75 | ZEND_MOD_REQUIRED("spl")
76 | ZEND_MOD_END
77 | };
78 |
79 | zend_module_entry ds_module_entry = {
80 | STANDARD_MODULE_HEADER_EX,
81 | NULL,
82 | ds_deps,
83 | "ds",
84 | NULL,
85 | PHP_MINIT(ds),
86 | NULL,
87 | PHP_RINIT(ds),
88 | PHP_RSHUTDOWN(ds),
89 | PHP_MINFO(ds),
90 | PHP_DS_VERSION,
91 | STANDARD_MODULE_PROPERTIES
92 | };
93 |
94 | #ifdef COMPILE_DL_DS
95 | #ifdef ZTS
96 | ZEND_TSRMLS_CACHE_DEFINE();
97 | #endif
98 | ZEND_GET_MODULE(ds)
99 | #endif
100 |
--------------------------------------------------------------------------------
/src/php/parameters.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_PARAMETERS_H
2 | #define DS_PARAMETERS_H
3 |
4 | #define SETUP_CALLABLE_VARS() \
5 | zend_fcall_info fci = empty_fcall_info; \
6 | zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
7 |
8 | #define PARSE_1(spec, a) if (zend_parse_parameters(ZEND_NUM_ARGS(), spec, a) == FAILURE) return
9 | #define PARSE_2(spec, a, b) if (zend_parse_parameters(ZEND_NUM_ARGS(), spec, a, b) == FAILURE) return
10 | #define PARSE_3(spec, a, b, c) if (zend_parse_parameters(ZEND_NUM_ARGS(), spec, a, b, c) == FAILURE) return
11 |
12 | #define PARSE_NONE if (zend_parse_parameters_none() == FAILURE) return
13 |
14 | #define PARSE_OPTIONAL_ZVAL(v) \
15 | zval *v = NULL; \
16 | PARSE_1("|z", &v)
17 |
18 | #define PARSE_OPTIONAL_ZVAL_OPTIONAL_ZVAL(v1, v2) \
19 | zval *v1 = NULL; \
20 | zval *v2 = NULL; \
21 | PARSE_2("|zz", &v1, &v2)
22 |
23 | #define PARSE_STRING() \
24 | char *str; \
25 | size_t len; \
26 | PARSE_2("s", &str, &len)
27 |
28 | #define PARSE_CALLABLE_AND_OPTIONAL_ZVAL(v) \
29 | SETUP_CALLABLE_VARS(); \
30 | zval *v = NULL; \
31 | PARSE_3("f|z", &fci, &fci_cache, &v)
32 |
33 | #define PARSE_CALLABLE() \
34 | SETUP_CALLABLE_VARS(); \
35 | PARSE_2("f", &fci, &fci_cache)
36 |
37 | #define PARSE_LONG_AND_LONG(a, b) \
38 | zend_long a = 0; \
39 | zend_long b = 0; \
40 | PARSE_2("ll", &a, &b)
41 |
42 | #define PARSE_LONG_AND_ZVAL(l, z) \
43 | zend_long l = 0; \
44 | zval *z = NULL; \
45 | PARSE_2("lz", &l, &z)
46 |
47 | #define PARSE_LONG_AND_OPTIONAL_ZVAL(l, z) \
48 | zend_long l = 0; \
49 | zval *z = NULL; \
50 | PARSE_2("l|z", &l, &z)
51 |
52 | #define PARSE_ZVAL_AND_LONG(z, l) \
53 | zval *z = NULL; \
54 | zend_long l = 0; \
55 | PARSE_2("zl", &z, &l)
56 |
57 | #define PARSE_VARIADIC_ZVAL() \
58 | zval *argv = NULL; \
59 | int argc = 0; \
60 | PARSE_2("*", &argv, &argc)
61 |
62 | #define PARSE_LONG_AND_VARIADIC_ZVAL(_l) \
63 | zval *argv = NULL; \
64 | int argc = 0; \
65 | zend_long _l = 0; \
66 | PARSE_3("l*", &_l, &argv, &argc)
67 |
68 | #define PARSE_LONG(a) \
69 | zend_long a = 0; \
70 | PARSE_1("l", &a)
71 |
72 | #define PARSE_COMPARE_CALLABLE() \
73 | DSG(user_compare_fci) = empty_fcall_info; \
74 | DSG(user_compare_fci_cache) = empty_fcall_info_cache; \
75 | PARSE_2("f", &DSG(user_compare_fci), &DSG(user_compare_fci_cache))
76 |
77 | #define PARSE_ZVAL(z) \
78 | zval *z = NULL; \
79 | PARSE_1("z", &z)
80 |
81 | #define PARSE_OBJ(o, ce) \
82 | zval *o = NULL; \
83 | PARSE_2("O", &o, ce)
84 |
85 | #define PARSE_ZVAL_ZVAL(z1, z2) \
86 | zval *z1 = NULL; \
87 | zval *z2 = NULL; \
88 | PARSE_2("zz", &z1, &z2)
89 |
90 | #define PARSE_ZVAL_OPTIONAL_ZVAL(z1, z2) \
91 | zval *z1 = NULL; \
92 | zval *z2 = NULL; \
93 | PARSE_2("z|z", &z1, &z2)
94 |
95 | #endif
96 |
--------------------------------------------------------------------------------
/src/php/objects/php_set.c:
--------------------------------------------------------------------------------
1 | #include "../iterators/php_set_iterator.h"
2 | #include "../handlers/php_set_handlers.h"
3 | #include "../classes/php_set_ce.h"
4 |
5 | #include "php_set.h"
6 |
7 | zend_object *php_ds_set_create_object_ex(ds_set_t *set)
8 | {
9 | #if PHP_VERSION_ID < 70300
10 | php_ds_set_t *obj = ecalloc(1, sizeof(php_ds_set_t) + zend_object_properties_size(php_ds_set_ce));
11 | #else
12 | php_ds_set_t *obj = zend_object_alloc(sizeof(php_ds_set_t), php_ds_set_ce);
13 | #endif
14 | zend_object_std_init(&obj->std, php_ds_set_ce);
15 | obj->std.handlers = &php_ds_set_handlers;
16 | obj->set = set;
17 | return &obj->std;
18 | }
19 |
20 | zend_object *php_ds_set_create_object(zend_class_entry *ce)
21 | {
22 | return php_ds_set_create_object_ex(ds_set());
23 | }
24 |
25 | zend_object *php_ds_set_create_clone(ds_set_t *set)
26 | {
27 | return php_ds_set_create_object_ex(ds_set_clone(set));
28 | }
29 |
30 | int php_ds_set_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data)
31 | {
32 | ds_set_t *set = Z_DS_SET_P(object);
33 |
34 | php_serialize_data_t serialize_data = (php_serialize_data_t) data;
35 | PHP_VAR_SERIALIZE_INIT(serialize_data);
36 |
37 | if (set->table->size == 0) {
38 | SERIALIZE_SET_ZSTR(ZSTR_EMPTY_ALLOC());
39 |
40 | } else {
41 |
42 | zval *key;
43 | smart_str buf = {0};
44 |
45 | DS_HTABLE_FOREACH_KEY(set->table, key) {
46 | php_var_serialize(&buf, key, &serialize_data);
47 | }
48 | DS_HTABLE_FOREACH_END();
49 |
50 | smart_str_0(&buf);
51 | SERIALIZE_SET_ZSTR(buf.s);
52 | zend_string_release(buf.s);
53 | }
54 |
55 | PHP_VAR_SERIALIZE_DESTROY(serialize_data);
56 | return SUCCESS;
57 | }
58 |
59 | int php_ds_set_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data)
60 | {
61 | ds_set_t *set = ds_set();
62 |
63 | php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data;
64 |
65 | const unsigned char *pos = buffer;
66 | const unsigned char *end = buffer + length;
67 |
68 | PHP_VAR_UNSERIALIZE_INIT(unserialize_data);
69 | ZVAL_DS_SET(object, set);
70 |
71 | while (pos != end) {
72 | zval *value = var_tmp_var(&unserialize_data);
73 |
74 | if ( ! php_var_unserialize(value, &pos, end, &unserialize_data)) {
75 | goto error;
76 | }
77 |
78 | ds_set_add(set, value);
79 | }
80 |
81 | PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
82 | return SUCCESS;
83 |
84 | error:
85 | ds_set_free(set);
86 | PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
87 | UNSERIALIZE_ERROR();
88 | return FAILURE;
89 | }
90 |
--------------------------------------------------------------------------------
/src/php/objects/php_deque.c:
--------------------------------------------------------------------------------
1 | // #include "../iterators/php_deque_iterator.h"
2 | #include "../handlers/php_deque_handlers.h"
3 | #include "../classes/php_deque_ce.h"
4 |
5 | #include "php_deque.h"
6 |
7 | zend_object *php_ds_deque_create_object_ex(ds_deque_t *deque)
8 | {
9 | #if PHP_VERSION_ID < 70300
10 | php_ds_deque_t *obj = ecalloc(1, sizeof(php_ds_deque_t) + zend_object_properties_size(php_ds_deque_ce));
11 | #else
12 | php_ds_deque_t *obj = zend_object_alloc(sizeof(php_ds_deque_t), php_ds_deque_ce);
13 | #endif
14 | zend_object_std_init(&obj->std, php_ds_deque_ce);
15 | obj->std.handlers = &php_deque_handlers;
16 | obj->deque = deque;
17 | return &obj->std;
18 | }
19 |
20 | zend_object *php_ds_deque_create_object(zend_class_entry *ce)
21 | {
22 | return php_ds_deque_create_object_ex(ds_deque());
23 | }
24 |
25 | zend_object *php_ds_deque_create_clone(ds_deque_t *deque)
26 | {
27 | return php_ds_deque_create_object_ex(ds_deque_clone(deque));
28 | }
29 |
30 | int php_ds_deque_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data)
31 | {
32 | ds_deque_t *deque = Z_DS_DEQUE_P(object);
33 |
34 | php_serialize_data_t serialize_data = (php_serialize_data_t) data;
35 | PHP_VAR_SERIALIZE_INIT(serialize_data);
36 |
37 | if (deque->size == 0) {
38 | SERIALIZE_SET_ZSTR(ZSTR_EMPTY_ALLOC());
39 |
40 | } else {
41 |
42 | zval *value;
43 | smart_str buf = {0};
44 |
45 | DS_DEQUE_FOREACH(deque, value) {
46 | php_var_serialize(&buf, value, &serialize_data);
47 | }
48 | DS_DEQUE_FOREACH_END();
49 |
50 | smart_str_0(&buf);
51 | SERIALIZE_SET_ZSTR(buf.s);
52 | zend_string_release(buf.s);
53 | }
54 |
55 | PHP_VAR_SERIALIZE_DESTROY(serialize_data);
56 | return SUCCESS;
57 | }
58 |
59 | int php_ds_deque_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data)
60 | {
61 | ds_deque_t *deque = ds_deque();
62 |
63 | php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data;
64 |
65 | const unsigned char *pos = buffer;
66 | const unsigned char *end = buffer + length;
67 |
68 | PHP_VAR_UNSERIALIZE_INIT(unserialize_data);
69 |
70 | while (pos != end) {
71 | zval *value = var_tmp_var(&unserialize_data);
72 |
73 | if ( ! php_var_unserialize(value, &pos, end, &unserialize_data)) {
74 | goto error;
75 | }
76 |
77 | ds_deque_push(deque, value);
78 | }
79 |
80 | ZVAL_DS_DEQUE(object, deque);
81 | PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
82 | return SUCCESS;
83 |
84 | error:
85 | ds_deque_free(deque);
86 | PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
87 | UNSERIALIZE_ERROR();
88 | return FAILURE;
89 | }
90 |
--------------------------------------------------------------------------------
/src/php/iterators/php_deque_iterator.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 |
3 | #include "../../ds/ds_deque.h"
4 | #include "../objects/php_deque.h"
5 | #include "php_deque_iterator.h"
6 |
7 | static void php_ds_deque_iterator_dtor(zend_object_iterator *iter)
8 | {
9 | php_ds_deque_iterator_t *iterator = (php_ds_deque_iterator_t *) iter;
10 |
11 | OBJ_RELEASE(iterator->object);
12 | }
13 |
14 | static int php_ds_deque_iterator_valid(zend_object_iterator *iter)
15 | {
16 | php_ds_deque_iterator_t *iterator = (php_ds_deque_iterator_t *) iter;
17 |
18 | if (iterator->position < iterator->deque->size) {
19 | return SUCCESS;
20 | }
21 |
22 | return FAILURE;
23 | }
24 |
25 | static zval *php_ds_deque_iterator_get_current_data(zend_object_iterator *iter)
26 | {
27 | php_ds_deque_iterator_t *iterator = (php_ds_deque_iterator_t *) iter;
28 | return ds_deque_get(iterator->deque, iterator->position);
29 | }
30 |
31 | static void php_ds_deque_iterator_get_current_key(zend_object_iterator *iter, zval *key) {
32 | ZVAL_LONG(key, ((php_ds_deque_iterator_t *) iter)->position);
33 | }
34 |
35 | static void php_ds_deque_iterator_move_forward(zend_object_iterator *iter)
36 | {
37 | ((php_ds_deque_iterator_t *) iter)->position++;
38 | }
39 |
40 | static void php_ds_deque_iterator_rewind(zend_object_iterator *iter)
41 | {
42 | ((php_ds_deque_iterator_t *) iter)->position = 0;
43 | }
44 |
45 | static zend_object_iterator_funcs iterator_funcs = {
46 | php_ds_deque_iterator_dtor,
47 | php_ds_deque_iterator_valid,
48 | php_ds_deque_iterator_get_current_data,
49 | php_ds_deque_iterator_get_current_key,
50 | php_ds_deque_iterator_move_forward,
51 | php_ds_deque_iterator_rewind
52 | };
53 |
54 | static zend_object_iterator *php_ds_deque_create_iterator(zval *obj, int by_ref)
55 | {
56 | php_ds_deque_iterator_t *iterator;
57 |
58 | if (by_ref) {
59 | ITERATION_BY_REF_NOT_SUPPORTED();
60 | return NULL;
61 | }
62 |
63 | iterator = ecalloc(1, sizeof(php_ds_deque_iterator_t));
64 | zend_iterator_init((zend_object_iterator*) iterator);
65 |
66 | iterator->intern.funcs = &iterator_funcs;
67 | iterator->deque = Z_DS_DEQUE_P(obj);
68 | iterator->object = Z_OBJ_P(obj);
69 | iterator->position = 0;
70 |
71 | // Add a reference to the object so that it doesn't get collected when
72 | // the iterated object is implict, eg. foreach ($obj->getInstance() as $value){ ... }
73 | #if PHP_VERSION_ID >= 70300
74 | GC_ADDREF(iterator->object);
75 | #else
76 | ++GC_REFCOUNT(iterator->object);
77 | #endif
78 |
79 | return (zend_object_iterator *) iterator;
80 | }
81 |
82 | zend_object_iterator *php_ds_deque_get_iterator(zend_class_entry *ce, zval *obj, int by_ref)
83 | {
84 | return php_ds_deque_create_iterator(obj, by_ref);
85 | }
86 |
--------------------------------------------------------------------------------
/config.w32:
--------------------------------------------------------------------------------
1 | // vim:ft=javascript
2 |
3 | var DS_EXT_NAME="ds";
4 | var DS_EXT_DIR=configure_module_dirname + "/src";
5 | var DS_EXT_API="php_ds.c";
6 | var DS_EXT_FLAGS="/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 /I" + configure_module_dirname;
7 |
8 | function ds_src(dir, files) {
9 | return ADD_SOURCES(
10 | DS_EXT_DIR + dir,
11 | files.join(" "),
12 | DS_EXT_NAME
13 | );
14 | }
15 |
16 | ////////////////////////////////////
17 | ARG_ENABLE("ds", "for extended data structure support", "no");
18 |
19 | if (PHP_DS != "no") {
20 | EXTENSION(DS_EXT_NAME, DS_EXT_API, PHP_DS_SHARED, DS_EXT_FLAGS);
21 |
22 | ds_src("/",
23 | [
24 | "common.c"
25 | ]);
26 |
27 | ds_src("/ds",
28 | [
29 | "ds_deque.c",
30 | "ds_vector.c",
31 | "ds_htable.c",
32 | "ds_set.c",
33 | "ds_map.c",
34 | "ds_stack.c",
35 | "ds_priority_queue.c",
36 | "ds_queue.c",
37 | ]);
38 |
39 | ds_src("/php/objects",
40 | [
41 | "php_deque.c",
42 | "php_vector.c",
43 | "php_map.c",
44 | "php_pair.c",
45 | "php_priority_queue.c",
46 | "php_set.c",
47 | "php_stack.c",
48 | "php_queue.c",
49 | ]);
50 |
51 | ds_src("/php/iterators",
52 | [
53 | "php_vector_iterator.c",
54 | "php_deque_iterator.c",
55 | "php_set_iterator.c",
56 | "php_map_iterator.c",
57 | "php_stack_iterator.c",
58 | "php_htable_iterator.c",
59 | "php_priority_queue_iterator.c",
60 | "php_queue_iterator.c",
61 | ]);
62 |
63 | ds_src("/php/handlers",
64 | [
65 | "php_common_handlers.c",
66 | "php_vector_handlers.c",
67 | "php_deque_handlers.c",
68 | "php_set_handlers.c",
69 | "php_map_handlers.c",
70 | "php_stack_handlers.c",
71 | "php_pair_handlers.c",
72 | "php_priority_queue_handlers.c",
73 | "php_queue_handlers.c",
74 | ]);
75 |
76 | ds_src("/php/classes",
77 | [
78 | "php_hashable_ce.c",
79 | "php_collection_ce.c",
80 | "php_sequence_ce.c",
81 | "php_vector_ce.c",
82 | "php_deque_ce.c",
83 | "php_set_ce.c",
84 | "php_map_ce.c",
85 | "php_stack_ce.c",
86 | "php_pair_ce.c",
87 | "php_priority_queue_ce.c",
88 | "php_queue_ce.c",
89 | ]);
90 |
91 | ADD_EXTENSION_DEP('ds', 'spl');
92 | var dll = get_define('PHPDLL');
93 | if (null != dll.match(/^php7/)) {
94 | // only require dynamic json extension for PHP 7
95 | // json is built statically in PHP 8
96 | // https://github.com/php/php-src/pull/5495
97 | ADD_EXTENSION_DEP('ds', 'json');
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/php/objects/php_queue.c:
--------------------------------------------------------------------------------
1 | #include "../iterators/php_queue_iterator.h"
2 | #include "../handlers/php_queue_handlers.h"
3 | #include "../classes/php_queue_ce.h"
4 |
5 | #include "php_queue.h"
6 |
7 | zend_object *php_ds_queue_create_object_ex(ds_queue_t *queue)
8 | {
9 | #if PHP_VERSION_ID < 70300
10 | php_ds_queue_t *obj = ecalloc(1, sizeof(php_ds_queue_t) + zend_object_properties_size(php_ds_queue_ce));
11 | #else
12 | php_ds_queue_t *obj = zend_object_alloc(sizeof(php_ds_queue_t), php_ds_queue_ce);
13 | #endif
14 | zend_object_std_init(&obj->std, php_ds_queue_ce);
15 | obj->std.handlers = &php_queue_handlers;
16 | obj->queue = queue;
17 |
18 | return &obj->std;
19 | }
20 |
21 | zend_object *php_ds_queue_create_object(zend_class_entry *ce)
22 | {
23 | return php_ds_queue_create_object_ex(ds_queue());
24 | }
25 |
26 | zend_object *php_ds_queue_create_clone(ds_queue_t *queue)
27 | {
28 | return php_ds_queue_create_object_ex(ds_queue_clone(queue));
29 | }
30 |
31 | int php_ds_queue_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data)
32 | {
33 | ds_queue_t *queue = Z_DS_QUEUE_P(object);
34 |
35 | php_serialize_data_t serialize_data = (php_serialize_data_t) data;
36 | PHP_VAR_SERIALIZE_INIT(serialize_data);
37 |
38 | if (QUEUE_SIZE(queue) == 0) {
39 | SERIALIZE_SET_ZSTR(ZSTR_EMPTY_ALLOC());
40 |
41 | } else {
42 |
43 | zval *value;
44 | smart_str buf = {0};
45 |
46 | DS_DEQUE_FOREACH(queue->deque, value) {
47 | php_var_serialize(&buf, value, &serialize_data);
48 | }
49 | DS_DEQUE_FOREACH_END();
50 |
51 | smart_str_0(&buf);
52 | SERIALIZE_SET_ZSTR(buf.s);
53 | zend_string_release(buf.s);
54 | }
55 |
56 | PHP_VAR_SERIALIZE_DESTROY(serialize_data);
57 | return SUCCESS;
58 | }
59 |
60 | int php_ds_queue_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data)
61 | {
62 | ds_queue_t *queue = ds_queue();
63 |
64 | php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data;
65 |
66 | const unsigned char *pos = buffer;
67 | const unsigned char *end = buffer + length;
68 |
69 | PHP_VAR_UNSERIALIZE_INIT(unserialize_data);
70 |
71 | while (pos != end) {
72 | zval *value = var_tmp_var(&unserialize_data);
73 |
74 | if ( ! php_var_unserialize(value, &pos, end, &unserialize_data)) {
75 | goto error;
76 | }
77 |
78 | ds_queue_push_one(queue, value);
79 | }
80 |
81 | ZVAL_DS_QUEUE(object, queue);
82 | PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
83 | return SUCCESS;
84 |
85 | error:
86 | ds_queue_free(queue);
87 | PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
88 | UNSERIALIZE_ERROR();
89 | return FAILURE;
90 | }
91 |
--------------------------------------------------------------------------------
/src/php/objects/php_stack.c:
--------------------------------------------------------------------------------
1 | #include "../iterators/php_stack_iterator.h"
2 | #include "../handlers/php_stack_handlers.h"
3 | #include "../classes/php_stack_ce.h"
4 |
5 | #include "php_stack.h"
6 |
7 | zend_object *php_ds_stack_create_object_ex(ds_stack_t *stack)
8 | {
9 | #if PHP_VERSION_ID < 70300
10 | php_ds_stack_t *obj = ecalloc(1, sizeof(php_ds_stack_t) + zend_object_properties_size(php_ds_stack_ce));
11 | #else
12 | php_ds_stack_t *obj = zend_object_alloc(sizeof(php_ds_stack_t), php_ds_stack_ce);
13 | #endif
14 | zend_object_std_init(&obj->std, php_ds_stack_ce);
15 | obj->std.handlers = &php_ds_stack_handlers;
16 | obj->stack = stack;
17 | return &obj->std;
18 | }
19 |
20 | zend_object *php_ds_stack_create_object(zend_class_entry *ce)
21 | {
22 | return php_ds_stack_create_object_ex(ds_stack());
23 | }
24 |
25 | zend_object *php_ds_stack_create_clone(ds_stack_t *stack)
26 | {
27 | return php_ds_stack_create_object_ex(ds_stack_clone(stack));
28 | }
29 |
30 | int php_ds_stack_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data)
31 | {
32 | ds_stack_t *stack = Z_DS_STACK_P(object);
33 |
34 | php_serialize_data_t serialize_data = (php_serialize_data_t) data;
35 | PHP_VAR_SERIALIZE_INIT(serialize_data);
36 |
37 | if (DS_STACK_SIZE(stack) == 0) {
38 | SERIALIZE_SET_ZSTR(ZSTR_EMPTY_ALLOC());
39 |
40 | } else {
41 |
42 | zval *value;
43 | smart_str buf = {0};
44 |
45 | DS_VECTOR_FOREACH(stack->vector, value) {
46 | php_var_serialize(&buf, value, &serialize_data);
47 | }
48 | DS_VECTOR_FOREACH_END();
49 |
50 | smart_str_0(&buf);
51 | SERIALIZE_SET_ZSTR(buf.s);
52 | zend_string_release(buf.s);
53 | }
54 |
55 | PHP_VAR_SERIALIZE_DESTROY(serialize_data);
56 | return SUCCESS;
57 | }
58 |
59 | int php_ds_stack_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data)
60 | {
61 | ds_stack_t *stack = ds_stack();
62 |
63 | php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data;
64 |
65 | const unsigned char *pos = buffer;
66 | const unsigned char *end = buffer + length;
67 |
68 | PHP_VAR_UNSERIALIZE_INIT(unserialize_data);
69 |
70 | while (pos != end) {
71 | zval *value = var_tmp_var(&unserialize_data);
72 |
73 | if ( ! php_var_unserialize(value, &pos, end, &unserialize_data)) {
74 | goto error;
75 | }
76 |
77 | ds_stack_push(stack, value);
78 | }
79 |
80 | ZVAL_DS_STACK(object, stack);
81 | PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
82 | return SUCCESS;
83 |
84 | error:
85 | ds_stack_free(stack);
86 | PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
87 | UNSERIALIZE_ERROR();
88 | return FAILURE;
89 | }
90 |
--------------------------------------------------------------------------------
/src/php/iterators/php_vector_iterator.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 |
3 | #include "../../ds/ds_vector.h"
4 | #include "../objects/php_vector.h"
5 | #include "php_vector_iterator.h"
6 |
7 | static void php_ds_vector_iterator_dtor(zend_object_iterator *iter)
8 | {
9 | php_ds_vector_iterator_t *iterator = (php_ds_vector_iterator_t *) iter;
10 |
11 | OBJ_RELEASE(iterator->object);
12 | }
13 |
14 | static int php_ds_vector_iterator_valid(zend_object_iterator *iter)
15 | {
16 | php_ds_vector_iterator_t *iterator = (php_ds_vector_iterator_t *) iter;
17 |
18 | return iterator->position < iterator->vector->size ? SUCCESS : FAILURE;
19 | }
20 |
21 | static zval *php_ds_vector_iterator_get_current_data(zend_object_iterator *iter)
22 | {
23 | php_ds_vector_iterator_t *iterator = (php_ds_vector_iterator_t *) iter;
24 |
25 | return &iterator->vector->buffer[iterator->position];
26 | }
27 |
28 | static void php_ds_vector_iterator_get_current_key(zend_object_iterator *iter, zval *key)
29 | {
30 | ZVAL_LONG(key, ((php_ds_vector_iterator_t *) iter)->position);
31 | }
32 |
33 | static void php_ds_vector_iterator_move_forward(zend_object_iterator *iter)
34 | {
35 | ((php_ds_vector_iterator_t *) iter)->position++;
36 | }
37 |
38 | static void php_ds_vector_iterator_rewind(zend_object_iterator *iter)
39 | {
40 | ((php_ds_vector_iterator_t *) iter)->position = 0;
41 | }
42 |
43 | static zend_object_iterator_funcs php_ds_vector_iterator_funcs = {
44 | php_ds_vector_iterator_dtor,
45 | php_ds_vector_iterator_valid,
46 | php_ds_vector_iterator_get_current_data,
47 | php_ds_vector_iterator_get_current_key,
48 | php_ds_vector_iterator_move_forward,
49 | php_ds_vector_iterator_rewind
50 | };
51 |
52 | static zend_object_iterator *php_ds_vector_create_iterator(zval *obj, int by_ref)
53 | {
54 | php_ds_vector_iterator_t *iterator;
55 |
56 | if (by_ref) {
57 | ITERATION_BY_REF_NOT_SUPPORTED();
58 | return NULL;
59 | }
60 |
61 | iterator = ecalloc(1, sizeof(php_ds_vector_iterator_t));
62 |
63 | zend_iterator_init((zend_object_iterator*) iterator);
64 |
65 | iterator->intern.funcs = &php_ds_vector_iterator_funcs;
66 | iterator->vector = Z_DS_VECTOR_P(obj);
67 | iterator->object = Z_OBJ_P(obj);
68 | iterator->position = 0;
69 |
70 | // Add a reference to the object so that it doesn't get collected when
71 | // the iterated object is implict, eg. foreach ($obj->getInstance() as $value){ ... }
72 | #if PHP_VERSION_ID >= 70300
73 | GC_ADDREF(iterator->object);
74 | #else
75 | ++GC_REFCOUNT(iterator->object);
76 | #endif
77 |
78 | return (zend_object_iterator *) iterator;
79 | }
80 |
81 | zend_object_iterator *php_ds_vector_get_iterator(zend_class_entry *ce, zval *obj, int by_ref)
82 | {
83 | return php_ds_vector_create_iterator(obj, by_ref);
84 | }
85 |
--------------------------------------------------------------------------------
/src/php/iterators/php_queue_iterator.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 | #include "../objects/php_queue.h"
3 | #include "php_queue_iterator.h"
4 |
5 | static void php_ds_queue_iterator_dtor(zend_object_iterator *iter)
6 | {
7 | ds_queue_iterator_t *iterator = (ds_queue_iterator_t *) iter;
8 |
9 | OBJ_RELEASE(iterator->object);
10 | }
11 |
12 | static int php_ds_queue_iterator_valid(zend_object_iterator *iter)
13 | {
14 | return Z_ISUNDEF(iter->data) ? FAILURE : SUCCESS;
15 | }
16 |
17 | static zval *php_ds_queue_iterator_get_current_data(zend_object_iterator *iter)
18 | {
19 | return &iter->data;
20 | }
21 |
22 | static void php_ds_queue_iterator_get_current_key(zend_object_iterator *iter, zval *key) {
23 | ZVAL_LONG(key, ((ds_queue_iterator_t *) iter)->position);
24 | }
25 |
26 | static void php_ds_queue_iterator_set_current(ds_queue_t *queue, zval *data)
27 | {
28 | if (QUEUE_IS_EMPTY(queue)) {
29 | ZVAL_UNDEF(data);
30 | } else {
31 | ds_queue_pop(queue, data);
32 | Z_TRY_DELREF_P(data);
33 | }
34 | }
35 |
36 | static void php_ds_queue_iterator_move_forward(zend_object_iterator *iter)
37 | {
38 | ds_queue_iterator_t *iterator = (ds_queue_iterator_t *) iter;
39 | php_ds_queue_iterator_set_current(iterator->queue, &iter->data);
40 | iterator->position++;
41 | }
42 |
43 | static void php_ds_queue_iterator_rewind(zend_object_iterator *iter)
44 | {
45 | ds_queue_iterator_t *iterator = (ds_queue_iterator_t *) iter;
46 | php_ds_queue_iterator_set_current(iterator->queue, &iter->data);
47 | iterator->position = 0;
48 | }
49 |
50 | static zend_object_iterator_funcs php_ds_queue_iterator_funcs = {
51 | php_ds_queue_iterator_dtor,
52 | php_ds_queue_iterator_valid,
53 | php_ds_queue_iterator_get_current_data,
54 | php_ds_queue_iterator_get_current_key,
55 | php_ds_queue_iterator_move_forward,
56 | php_ds_queue_iterator_rewind
57 | };
58 |
59 | zend_object_iterator *php_ds_queue_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
60 | {
61 | ds_queue_iterator_t *iterator;
62 |
63 | if (by_ref) {
64 | ITERATION_BY_REF_NOT_SUPPORTED();
65 | return NULL;
66 | }
67 |
68 | iterator = ecalloc(1, sizeof(ds_queue_iterator_t));
69 | zend_iterator_init((zend_object_iterator*) iterator);
70 |
71 | iterator->intern.funcs = &php_ds_queue_iterator_funcs;
72 | iterator->queue = Z_DS_QUEUE_P(object);
73 | iterator->object = Z_OBJ_P(object);
74 | iterator->position = 0;
75 |
76 | // Add a reference to the object so that it doesn't get collected when
77 | // the iterated object is implict, eg. foreach ($obj->getInstance() as $value){ ... }
78 | #if PHP_VERSION_ID >= 70300
79 | GC_ADDREF(iterator->object);
80 | #else
81 | ++GC_REFCOUNT(iterator->object);
82 | #endif
83 |
84 | return (zend_object_iterator *) iterator;
85 | }
86 |
--------------------------------------------------------------------------------
/src/php/objects/php_vector.c:
--------------------------------------------------------------------------------
1 | // #include "../iterators/php_vector_iterator.h"
2 | #include "../handlers/php_vector_handlers.h"
3 | #include "../classes/php_vector_ce.h"
4 |
5 | #include "php_vector.h"
6 |
7 | zend_object *php_ds_vector_create_object_ex(ds_vector_t *vector)
8 | {
9 | #if PHP_VERSION_ID < 70300
10 | php_ds_vector_t *obj = ecalloc(1, sizeof(php_ds_vector_t) + zend_object_properties_size(php_ds_vector_ce));
11 | #else
12 | php_ds_vector_t *obj = zend_object_alloc(sizeof(php_ds_vector_t), php_ds_vector_ce);
13 | #endif
14 | zend_object_std_init(&obj->std, php_ds_vector_ce);
15 | obj->std.handlers = &php_vector_handlers;
16 | obj->vector = vector;
17 |
18 | return &obj->std;
19 | }
20 |
21 | zend_object *php_ds_vector_create_object(zend_class_entry *ce)
22 | {
23 | return php_ds_vector_create_object_ex(ds_vector());
24 | }
25 |
26 | zend_object *php_ds_vector_create_clone(ds_vector_t *vector)
27 | {
28 | return php_ds_vector_create_object_ex(ds_vector_clone(vector));
29 | }
30 |
31 | int php_ds_vector_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data)
32 | {
33 | ds_vector_t *vector = Z_DS_VECTOR_P(object);
34 |
35 | php_serialize_data_t serialize_data = (php_serialize_data_t) data;
36 | PHP_VAR_SERIALIZE_INIT(serialize_data);
37 |
38 | if (DS_VECTOR_IS_EMPTY(vector)) {
39 | SERIALIZE_SET_ZSTR(ZSTR_EMPTY_ALLOC());
40 |
41 | } else {
42 | zval *value;
43 | smart_str buf = {0};
44 |
45 | DS_VECTOR_FOREACH(vector, value) {
46 | php_var_serialize(&buf, value, &serialize_data);
47 | }
48 | DS_VECTOR_FOREACH_END();
49 |
50 | smart_str_0(&buf);
51 | SERIALIZE_SET_ZSTR(buf.s);
52 | zend_string_release(buf.s);
53 | }
54 |
55 | PHP_VAR_SERIALIZE_DESTROY(serialize_data);
56 | return SUCCESS;
57 | }
58 |
59 | int php_ds_vector_unserialize(zval *obj, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data)
60 | {
61 | ds_vector_t *vector = ds_vector();
62 |
63 | php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data;
64 |
65 | const unsigned char *pos = buffer;
66 | const unsigned char *end = buffer + length;
67 |
68 | PHP_VAR_UNSERIALIZE_INIT(unserialize_data);
69 |
70 | while (pos != end) {
71 | zval *value = var_tmp_var(&unserialize_data);
72 |
73 | if ( ! php_var_unserialize(value, &pos, end, &unserialize_data)) {
74 | goto error;
75 | }
76 |
77 | ds_vector_push(vector, value);
78 | }
79 |
80 | ZVAL_DS_VECTOR(obj, vector);
81 | PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
82 | return SUCCESS;
83 |
84 | error:
85 | ds_vector_free(vector);
86 | PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
87 | UNSERIALIZE_ERROR();
88 | return FAILURE;
89 | }
90 |
--------------------------------------------------------------------------------
/src/php/iterators/php_stack_iterator.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 | #include "../objects/php_stack.h"
3 | #include "php_stack_iterator.h"
4 |
5 | static void php_ds_stack_iterator_dtor(zend_object_iterator *iter)
6 | {
7 | php_ds_stack_iterator_t *iterator = (php_ds_stack_iterator_t *) iter;
8 |
9 | OBJ_RELEASE(iterator->object);
10 | }
11 |
12 | static int php_ds_stack_iterator_valid(zend_object_iterator *iter)
13 | {
14 | return Z_ISUNDEF(iter->data) ? FAILURE : SUCCESS;
15 | }
16 |
17 | static zval *php_ds_stack_iterator_get_current_data(zend_object_iterator *iter)
18 | {
19 | return &iter->data;
20 | }
21 |
22 | static void php_ds_stack_iterator_get_current_key(zend_object_iterator *iter, zval *key) {
23 | ZVAL_LONG(key, ((php_ds_stack_iterator_t *) iter)->position);
24 | }
25 |
26 | static void php_ds_stack_iterator_set_current(ds_stack_t *stack, zval *data)
27 | {
28 | if (DS_STACK_IS_EMPTY(stack)) {
29 | ZVAL_UNDEF(data);
30 | } else {
31 | ds_stack_pop(stack, data);
32 | Z_TRY_DELREF_P(data);
33 | }
34 | }
35 |
36 | static void php_ds_stack_iterator_move_forward(zend_object_iterator *iter)
37 | {
38 | php_ds_stack_iterator_t *iterator = (php_ds_stack_iterator_t *) iter;
39 | php_ds_stack_iterator_set_current(iterator->stack, &iter->data);
40 | iterator->position++;
41 | }
42 |
43 | static void php_ds_stack_iterator_rewind(zend_object_iterator *iter)
44 | {
45 | php_ds_stack_iterator_t *iterator = (php_ds_stack_iterator_t *) iter;
46 | php_ds_stack_iterator_set_current(iterator->stack, &iter->data);
47 | iterator->position = 0;
48 | }
49 |
50 | static zend_object_iterator_funcs php_ds_stack_iterator_funcs = {
51 | php_ds_stack_iterator_dtor,
52 | php_ds_stack_iterator_valid,
53 | php_ds_stack_iterator_get_current_data,
54 | php_ds_stack_iterator_get_current_key,
55 | php_ds_stack_iterator_move_forward,
56 | php_ds_stack_iterator_rewind
57 | };
58 |
59 | zend_object_iterator *php_ds_stack_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
60 | {
61 | php_ds_stack_iterator_t *iterator;
62 |
63 | if (by_ref) {
64 | ITERATION_BY_REF_NOT_SUPPORTED();
65 | return NULL;
66 | }
67 |
68 | iterator = ecalloc(1, sizeof(php_ds_stack_iterator_t));
69 | zend_iterator_init((zend_object_iterator*) iterator);
70 |
71 | iterator->intern.funcs = &php_ds_stack_iterator_funcs;
72 | iterator->stack = Z_DS_STACK_P(object);
73 | iterator->object = Z_OBJ_P(object);
74 | iterator->position = 0;
75 |
76 | // Add a reference to the object so that it doesn't get collected when
77 | // the iterated object is implict, eg. foreach ($obj->getInstance() as $value){ ... }
78 | #if PHP_VERSION_ID >= 70300
79 | GC_ADDREF(iterator->object);
80 | #else
81 | ++GC_REFCOUNT(iterator->object);
82 | #endif
83 |
84 | return (zend_object_iterator *) iterator;
85 | }
86 |
--------------------------------------------------------------------------------
/src/php/classes/php_map_ce.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_MAP_CE_H
2 | #define DS_MAP_CE_H
3 |
4 | #include "php.h"
5 | #include "../../common.h"
6 | #include "../arginfo.h"
7 |
8 | extern zend_class_entry *php_ds_map_ce;
9 |
10 | ARGINFO_OPTIONAL_ZVAL( Map___construct, values);
11 | ARGINFO_LONG( Map_allocate, capacity);
12 | ARGINFO_CALLABLE( Map_apply, callback);
13 | ARGINFO_NONE_RETURN_LONG( Map_capacity);
14 | ARGINFO_ZVAL_ZVAL( Map_put, key, value);
15 | ARGINFO_ZVAL( Map_putAll, values);
16 | ARGINFO_ZVAL_OPTIONAL_ZVAL( Map_get, key, default);
17 | ARGINFO_DS_RETURN_DS( Map_intersect, map, Map, Map);
18 | ARGINFO_ZVAL_OPTIONAL_ZVAL( Map_remove, key, default);
19 | ARGINFO_ZVAL_RETURN_BOOL( Map_hasKey, key);
20 | ARGINFO_ZVAL_RETURN_BOOL( Map_hasValue, value);
21 | ARGINFO_DS_RETURN_DS( Map_diff, map, Map, Map);
22 | ARGINFO_OPTIONAL_CALLABLE( Map_sort, comparator);
23 | ARGINFO_OPTIONAL_CALLABLE_RETURN_DS( Map_sorted, comparator, Map);
24 | ARGINFO_OPTIONAL_CALLABLE( Map_ksort, comparator);
25 | ARGINFO_OPTIONAL_CALLABLE_RETURN_DS( Map_ksorted, comparator, Map);
26 | ARGINFO_NONE_RETURN_DS( Map_keys, Set);
27 | ARGINFO_NONE_RETURN_DS( Map_last, Pair);
28 | ARGINFO_ZVAL_RETURN_DS( Map_merge, values, Map);
29 | ARGINFO_NONE_RETURN_DS( Map_pairs, Sequence);
30 | ARGINFO_NONE_RETURN_TYPE( Map_jsonSerialize, IS_MIXED);
31 | ARGINFO_OPTIONAL_CALLABLE_RETURN_DS( Map_filter, callback, Map);
32 | ARGINFO_NONE_RETURN_DS( Map_first, Pair);
33 | ARGINFO_CALLABLE_OPTIONAL_ZVAL( Map_reduce, callback, initial);
34 | ARGINFO_NONE( Map_reverse);
35 | ARGINFO_NONE_RETURN_DS( Map_reversed, Map);
36 | ARGINFO_LONG_RETURN_DS( Map_skip, position, Pair);
37 | ARGINFO_CALLABLE_RETURN_DS( Map_map, callback, Map);
38 | ARGINFO_LONG_OPTIONAL_LONG_RETURN_DS( Map_slice, index, length, Map);
39 | ARGINFO_NONE( Map_sum);
40 | ARGINFO_ZVAL_RETURN_DS( Map_union, map, Map);
41 | ARGINFO_NONE_RETURN_DS( Map_values, Sequence);
42 | ARGINFO_DS_RETURN_DS( Map_xor, map, Map, Map);
43 | ARGINFO_NONE_RETURN_OBJ( Map_getIterator, Traversable);
44 |
45 | ARGINFO_ZVAL_RETURN_BOOL( Map_offsetExists, offset);
46 | ARGINFO_OFFSET_GET( Map_offsetGet);
47 | ARGINFO_OFFSET_SET( Map_offsetSet);
48 | ARGINFO_OFFSET_UNSET( Map_offsetUnset);
49 |
50 | void php_ds_register_map();
51 |
52 | #endif
53 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Native Data Structures for PHP
2 |
3 | [](https://github.com/php-ds/ext-ds/actions?query=workflow%3A%22CI%22+branch%3Amaster)
4 | [](https://ci.appveyor.com/project/rtheunissen/ext-ds)
5 | [](https://pecl.php.net/package/ds)
6 |
7 | A PHP language extension that provides specialized data structures as efficient alternatives to the PHP array.
8 | You can read about it in more detail [in this blog post](https://medium.com/p/9dda7af674cd) which highlights the API, performance (relative to PHP 7) and other benefits of using the extension.
9 |
10 | ## Documentation
11 |
12 | Documentation is available on [php.net](https://www.php.net/manual/en/book.ds.php). You should also include the [polyfill](https://github.com/php-ds/polyfill) in your project for IDE integration.
13 |
14 | ## Installation
15 |
16 | The easiest way to install the extension is to use PECL:
17 |
18 | ```
19 | pecl install ds
20 | ```
21 |
22 | If you're on Windows, you can download a compiled `.dll` on [PECL](https://pecl.php.net/package/ds) or under [releases](https://github.com/php-ds/extension/releases).
23 |
24 | ## Enabling the extension
25 |
26 | You'll need to add `extension=ds.so` to your primary `php.ini` file.
27 |
28 | If you encounter an "undefined symbol" error, see [#2](https://github.com/php-ds/extension/issues/2#issuecomment-181855047).
29 |
30 | ```bash
31 | # To see where .ini files are located
32 | php -i | grep "\.ini"
33 | ```
34 |
35 | ---
36 |
37 | You can also enable the extension temporarily using the command line:
38 |
39 | ```bash
40 | php -d extension=ds.so
41 | ```
42 |
43 | **Note**: Windows would use `php_ds.dll` instead.
44 |
45 | ## Testing
46 |
47 | There is a suite of PHPUnit tests that can be installed using [**Composer**](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx).
48 |
49 | ``` bash
50 | composer install # Install the test suite
51 | composer test # Run the tests
52 | composer memtest # Run the tests checking for memory leaks
53 | ```
54 |
55 | ## Compatibility
56 |
57 | You may include the [polyfill](https://github.com/php-ds/polyfill) as a dependency in your project. This allows your codebase to still function in an environment where the extension is not installed.
58 |
59 | ## Contributing
60 |
61 | For local development, I'm using Docker:
62 |
63 | ```
64 | ./dev.sh # opens a shell into a development environment
65 |
66 | phpize
67 | ./configure
68 | make
69 | make install
70 |
71 | composer install
72 | composer test
73 | ```
74 |
75 | Please see [CONTRIBUTING](CONTRIBUTING.md) for more information.
76 |
77 | ## Credits
78 |
79 | - [Rudi Theunissen](https://github.com/rtheunissen)
80 | - [Joe Watkins](https://github.com/krakjoe)
81 |
82 | ## License
83 |
84 | The MIT License (MIT). Please see [LICENSE](LICENSE) for more information.
85 |
--------------------------------------------------------------------------------
/src/ds/ds_priority_queue.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_PRIORITY_QUEUE_H
2 | #define DS_PRIORITY_QUEUE_H
3 |
4 | #include "../common.h"
5 |
6 | typedef struct _ds_priority_queue_node_t {
7 | zval value;
8 | zval priority;
9 | } ds_priority_queue_node_t;
10 |
11 | typedef struct _ds_priority_queue_t {
12 | ds_priority_queue_node_t *nodes;
13 | uint32_t capacity;
14 | uint32_t size;
15 | uint32_t next;
16 | } ds_priority_queue_t;
17 |
18 | #define DS_PRIORITY_QUEUE_MIN_CAPACITY 8
19 |
20 | #define DS_PRIORITY_QUEUE_FOREACH_NODE(queue, node) \
21 | do { \
22 | ds_priority_queue_t *_queue = queue; \
23 | ds_priority_queue_node_t *_node = &_queue->nodes[0]; \
24 | ds_priority_queue_node_t *_last = &_queue->nodes[queue->size - 1]; \
25 | \
26 | for (; _node <= _last; ++_node) { \
27 | node = _node;
28 |
29 |
30 | #define DS_PRIORITY_QUEUE_FOREACH_VALUE(queue, value) \
31 | ds_priority_queue_node_t *__node = NULL; \
32 | DS_PRIORITY_QUEUE_FOREACH_NODE(queue, __node) \
33 | value = &__node->value;
34 |
35 |
36 | #define DS_PRIORITY_QUEUE_FOREACH(queue, value, priority) \
37 | ds_priority_queue_node_t *__node = NULL; \
38 | DS_PRIORITY_QUEUE_FOREACH_NODE(queue, __node) \
39 | value = &__node->value; \
40 | priority = &__node->priority;
41 |
42 |
43 | #define DS_PRIORITY_QUEUE_FOREACH_END() \
44 | } \
45 | } while (0) \
46 |
47 | /**
48 | * Has to exist because of the uint32_t insertion order stamp.
49 | *
50 | * @todo this isn't necessary because we can re-index when the stamp == max int
51 | */
52 | #define DS_PRIORITY_QUEUE_MAX_CAPACITY (1 << 31)
53 |
54 | #define DS_PRIORITY_QUEUE_SIZE(queue) ((queue)->size)
55 | #define DS_PRIORITY_QUEUE_IS_EMPTY(queue) (DS_PRIORITY_QUEUE_SIZE(queue) == 0)
56 |
57 | ds_priority_queue_t *ds_priority_queue();
58 |
59 | void ds_priority_queue_allocate(ds_priority_queue_t *queue, uint32_t capacity);
60 |
61 | uint32_t ds_priority_queue_capacity(ds_priority_queue_t *queue);
62 |
63 | zval *ds_priority_queue_peek(ds_priority_queue_t *queue);
64 |
65 | void ds_priority_queue_pop(ds_priority_queue_t *queue, zval *return_value);
66 |
67 | void ds_priority_queue_push(ds_priority_queue_t *queue, zval *value, zval *priority);
68 |
69 | void ds_priority_queue_to_array(ds_priority_queue_t *queue, zval *array);
70 |
71 | void ds_priority_queue_free(ds_priority_queue_t *queue);
72 |
73 | void ds_priority_queue_clear(ds_priority_queue_t *queue);
74 |
75 | ds_priority_queue_t *ds_priority_queue_clone(ds_priority_queue_t * queue);
76 |
77 | ds_priority_queue_node_t* ds_priority_queue_create_sorted_buffer(ds_priority_queue_t *queue);
78 |
79 | #endif
80 |
--------------------------------------------------------------------------------
/src/php/handlers/php_priority_queue_handlers.c:
--------------------------------------------------------------------------------
1 | #include "php_common_handlers.h"
2 | #include "php_deque_handlers.h"
3 |
4 | #include "../objects/php_priority_queue.h"
5 | #include "../../ds/ds_priority_queue.h"
6 |
7 | zend_object_handlers php_priority_queue_handlers;
8 |
9 | static void php_ds_priority_queue_free_object(zend_object *object)
10 | {
11 | php_ds_priority_queue_t *queue = php_ds_priority_queue_fetch_object(object);
12 | ds_priority_queue_free(queue->queue);
13 |
14 | if (queue->gc_data != NULL) {
15 | efree(queue->gc_data);
16 | }
17 | zend_object_std_dtor(&queue->std);
18 | }
19 |
20 | static int php_ds_priority_queue_count_elements
21 | #if PHP_VERSION_ID >= 80000
22 | (zend_object *obj, zend_long *count) {
23 | ds_priority_queue_t *pq = php_ds_priority_queue_fetch_object(obj)->queue;
24 | #else
25 | (zval *obj, zend_long *count) {
26 | ds_priority_queue_t *pq = Z_DS_PRIORITY_QUEUE_P(obj);
27 | #endif
28 | *count = DS_PRIORITY_QUEUE_SIZE(pq);
29 | return SUCCESS;
30 | }
31 |
32 | static zend_object *php_ds_priority_queue_clone_obj
33 | #if PHP_VERSION_ID >= 80000
34 | (zend_object *obj) {
35 | ds_priority_queue_t *pq = php_ds_priority_queue_fetch_object(obj)->queue;
36 | #else
37 | (zval *obj) {
38 | ds_priority_queue_t *pq = Z_DS_PRIORITY_QUEUE_P(obj);
39 | #endif
40 | return php_ds_priority_queue_create_clone(pq);
41 | }
42 |
43 | static HashTable *php_ds_priority_queue_get_debug_info
44 | #if PHP_VERSION_ID >= 80000
45 | (zend_object *obj, int *is_temp) {
46 | ds_priority_queue_t *pq = php_ds_priority_queue_fetch_object(obj)->queue;
47 | #else
48 | (zval *obj, int *is_temp) {
49 | ds_priority_queue_t *pq = Z_DS_PRIORITY_QUEUE_P(obj);
50 | #endif
51 | zval arr;
52 | *is_temp = 1;
53 | ds_priority_queue_to_array(pq, &arr);
54 | return Z_ARRVAL(arr);
55 | }
56 |
57 | static HashTable *php_ds_priority_queue_get_gc
58 | #if PHP_VERSION_ID >= 80000
59 | (zend_object *obj, zval **gc_data, int *gc_size) {
60 | ds_priority_queue_t *pq = php_ds_priority_queue_fetch_object(obj)->queue;
61 | #else
62 | (zval *obj, zval **gc_data, int *gc_size) {
63 | ds_priority_queue_t *pq = Z_DS_PRIORITY_QUEUE_P(obj);
64 | #endif
65 | if (DS_PRIORITY_QUEUE_IS_EMPTY(pq)) {
66 | *gc_data = NULL;
67 | *gc_size = 0;
68 | } else {
69 | *gc_data = (zval*) pq->nodes;
70 | *gc_size = pq->size * 2;
71 | }
72 | return NULL;
73 | }
74 |
75 | void php_ds_register_priority_queue_handlers()
76 | {
77 | memcpy(&php_priority_queue_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
78 |
79 | php_priority_queue_handlers.offset = XtOffsetOf(php_ds_priority_queue_t, std);
80 |
81 | php_priority_queue_handlers.get_gc = php_ds_priority_queue_get_gc;
82 | php_priority_queue_handlers.free_obj = php_ds_priority_queue_free_object;
83 | php_priority_queue_handlers.clone_obj = php_ds_priority_queue_clone_obj;
84 | php_priority_queue_handlers.cast_object = php_ds_default_cast_object;
85 | php_priority_queue_handlers.get_debug_info = php_ds_priority_queue_get_debug_info;
86 | php_priority_queue_handlers.count_elements = php_ds_priority_queue_count_elements;
87 | }
88 |
--------------------------------------------------------------------------------
/src/php/iterators/php_priority_queue_iterator.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 |
3 | #include "../../ds/ds_priority_queue.h"
4 | #include "../objects/php_priority_queue.h"
5 | #include "php_priority_queue_iterator.h"
6 |
7 | static void php_ds_priority_queue_iterator_dtor(zend_object_iterator *iter)
8 | {
9 | php_ds_priority_queue_iterator *iterator = (php_ds_priority_queue_iterator *) iter;
10 |
11 | DTOR_AND_UNDEF(&iterator->intern.data);
12 | OBJ_RELEASE(iterator->object);
13 | }
14 |
15 | static int php_ds_priority_queue_iterator_valid(zend_object_iterator *iter)
16 | {
17 | return Z_ISUNDEF(iter->data) ? FAILURE : SUCCESS;
18 | }
19 |
20 | static zval *php_ds_priority_queue_iterator_get_current_data(zend_object_iterator *iter)
21 | {
22 | return &iter->data;
23 | }
24 |
25 | static void php_ds_priority_queue_iterator_get_current_key(zend_object_iterator *iter, zval *key) {
26 | ZVAL_LONG(key, ((php_ds_priority_queue_iterator *) iter)->position);
27 | }
28 |
29 | static void php_ds_priority_queue_iterator_set_current(ds_priority_queue_t *queue, zval *data)
30 | {
31 | if (DS_PRIORITY_QUEUE_IS_EMPTY(queue)) {
32 | ZVAL_UNDEF(data);
33 | } else {
34 | ds_priority_queue_pop(queue, data);
35 | Z_TRY_DELREF_P(data);
36 | }
37 | }
38 |
39 | static void php_ds_priority_queue_iterator_move_forward(zend_object_iterator *iter)
40 | {
41 | php_ds_priority_queue_iterator *iterator = (php_ds_priority_queue_iterator *) iter;
42 | php_ds_priority_queue_iterator_set_current(iterator->queue, &iter->data);
43 | iterator->position++;
44 | }
45 |
46 | static void php_ds_priority_queue_iterator_rewind(zend_object_iterator *iter)
47 | {
48 | php_ds_priority_queue_iterator *iterator = (php_ds_priority_queue_iterator *) iter;
49 | php_ds_priority_queue_iterator_set_current(iterator->queue, &iter->data);
50 | iterator->position = 0;
51 | }
52 |
53 | static zend_object_iterator_funcs iterator_funcs = {
54 | php_ds_priority_queue_iterator_dtor,
55 | php_ds_priority_queue_iterator_valid,
56 | php_ds_priority_queue_iterator_get_current_data,
57 | php_ds_priority_queue_iterator_get_current_key,
58 | php_ds_priority_queue_iterator_move_forward,
59 | php_ds_priority_queue_iterator_rewind
60 | };
61 |
62 | zend_object_iterator *php_ds_priority_queue_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
63 | {
64 | php_ds_priority_queue_iterator *iterator;
65 |
66 | if (by_ref) {
67 | ITERATION_BY_REF_NOT_SUPPORTED();
68 | return NULL;
69 | }
70 |
71 | iterator = ecalloc(1, sizeof(php_ds_priority_queue_iterator));
72 | zend_iterator_init((zend_object_iterator*) iterator);
73 |
74 | ZVAL_UNDEF(&iterator->intern.data);
75 |
76 | iterator->intern.funcs = &iterator_funcs;
77 | iterator->queue = Z_DS_PRIORITY_QUEUE_P(object);
78 | iterator->object = Z_OBJ_P(object);
79 | iterator->position = 0;
80 |
81 | // Add a reference to the object so that it doesn't get collected when
82 | // the iterated object is implict, eg. foreach ($obj->getInstance() as $value){ ... }
83 | #if PHP_VERSION_ID >= 70300
84 | GC_ADDREF(iterator->object);
85 | #else
86 | ++GC_REFCOUNT(iterator->object);
87 | #endif
88 |
89 | return (zend_object_iterator *) iterator;
90 | }
91 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: '{branch}.{build}'
2 |
3 | branches:
4 | only:
5 | - master
6 |
7 | image: Visual Studio 2017
8 |
9 | clone_folder: c:\projects\php-ds
10 |
11 | environment:
12 | PHP_SDK_BINARY_TOOLS_VER: php-sdk-2.1.1
13 |
14 | matrix:
15 | - ARCH: x86
16 | INT_SIZE: 32
17 | PHP_VER: 8.4
18 | VC_VER: vc15
19 | ZTS: --enable-zts
20 | - ARCH: x64
21 | INT_SIZE: 64
22 | PHP_VER: 8.4
23 | VC_VER: vc15
24 | ZTS: --enable-zts
25 | - ARCH: x86
26 | INT_SIZE: 32
27 | PHP_VER: 8.4
28 | VC_VER: vc15
29 | ZTS: --disable-zts
30 | - ARCH: x64
31 | INT_SIZE: 64
32 | PHP_VER: 8.4
33 | VC_VER: vc15
34 | ZTS: --disable-zts
35 |
36 | install:
37 | - cmd: choco feature enable -n=allowGlobalConfirmation
38 | - cmd: cinst wget
39 | - cmd: mkdir C:\projects\php-ds\bin
40 | - cmd: cd C:\projects\php-ds\bin && appveyor DownloadFile https://getcomposer.org/composer.phar
41 |
42 | build_script:
43 | - cmd: >-
44 | "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" %ARCH%
45 |
46 | wget https://github.com/OSTC/php-sdk-binary-tools/archive/%PHP_SDK_BINARY_TOOLS_VER%.zip --no-check-certificate -q -O php-sdk-binary-tools-%PHP_SDK_BINARY_TOOLS_VER%.zip
47 |
48 | 7z x -y php-sdk-binary-tools-%PHP_SDK_BINARY_TOOLS_VER%.zip -oC:\projects
49 |
50 | move C:\projects\php-sdk-binary-tools-%PHP_SDK_BINARY_TOOLS_VER% C:\projects\php-sdk
51 |
52 | C:\projects\php-sdk\bin\phpsdk_setvars.bat
53 |
54 | git clone https://github.com/php/php-src C:\projects\php-src -b PHP-%PHP_VER% --depth=1
55 |
56 | mkdir C:\projects\php-src\ext\ds
57 |
58 | xcopy C:\projects\php-ds C:\projects\php-src\ext\ds /s /e /y /q
59 |
60 | phpsdk_deps -u -t %VC_VER% -b %PHP_VER% -a %ARCH% -f -d C:\projects\php-src\deps
61 |
62 | cd C:\projects\php-src
63 |
64 | buildconf.bat
65 |
66 | cscript /nologo configure.js --disable-all --enable-cli --enable-cgi %ZTS% --with-openssl --enable-ds=shared --enable-phar --with-prefix=C:\projects\php-ds\bin --with-php-build=deps --with-config-file-scan-dir=C:\projects\php-ds\bin\modules.d --enable-bcmath --enable-calendar --enable-ctype --enable-filter --enable-hash --with-mhash --with-iconv --enable-json --enable-mbstring --with-readline --enable-session --enable-soap=shared --enable-tokenizer --enable-zip --enable-zlib --with-libxml --with-dom --with-simplexml --with-xml --with-wddx --enable-xmlreader --enable-xmlwriter
67 |
68 | nmake
69 |
70 | nmake install
71 |
72 | copy php.ini-development C:\projects\php-ds\bin\php.ini
73 |
74 | mkdir C:\projects\php-ds\bin\modules.d
75 |
76 | echo extension=php_ds.dll >> C:\projects\php-ds\bin\modules.d\php.ini
77 |
78 | echo extension=php_openssl.dll >> C:\projects\php-ds\bin\modules.d\php.ini
79 |
80 | echo extension=php_soap.dll >> C:\projects\php-ds\bin\modules.d\php.ini
81 |
82 | cd C:\projects\php-ds\bin
83 |
84 | set TEST_PHP_EXECUTABLE=%cd%\php.exe
85 |
86 | php -v
87 |
88 | php -m
89 |
90 | test_script:
91 | - cmd: cd C:\projects\php-ds
92 | - cmd: C:\projects\php-ds\bin\php.exe C:\projects\php-ds\bin\composer.phar update --prefer-source
93 | - cmd: C:\projects\php-ds\bin\php.exe test.php > test.txt
94 | - cmd: type test.txt
95 | - cmd: cd C:\projects\php-ds\bin
96 | - cmd: php.exe /projects/php-src/run-tests.php /projects/php-src/ext/ds -q --show-diff
97 |
98 | artifacts:
99 | - path: bin
100 | name: master
101 | type: zip
102 |
--------------------------------------------------------------------------------
/src/php/classes/php_priority_queue_ce.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 |
3 | #include "../parameters.h"
4 | #include "../arginfo.h"
5 |
6 | #include "../iterators/php_priority_queue_iterator.h"
7 | #include "../handlers/php_priority_queue_handlers.h"
8 | #include "../objects/php_priority_queue.h"
9 |
10 | #include "php_collection_ce.h"
11 | #include "php_priority_queue_ce.h"
12 |
13 | #define METHOD(name) PHP_METHOD(PriorityQueue, name)
14 |
15 | zend_class_entry *php_ds_priority_queue_ce;
16 |
17 | METHOD(__construct)
18 | {
19 | PARSE_NONE;
20 | }
21 |
22 | METHOD(allocate)
23 | {
24 | PARSE_LONG(capacity);
25 | ds_priority_queue_allocate(THIS_DS_PRIORITY_QUEUE(), capacity);
26 | }
27 |
28 | METHOD(capacity)
29 | {
30 | PARSE_NONE;
31 | RETURN_LONG(ds_priority_queue_capacity(THIS_DS_PRIORITY_QUEUE()));
32 | }
33 |
34 | METHOD(copy)
35 | {
36 | PARSE_NONE;
37 | RETURN_OBJ(php_ds_priority_queue_create_clone(THIS_DS_PRIORITY_QUEUE()));
38 | }
39 |
40 | METHOD(push)
41 | {
42 | PARSE_ZVAL_ZVAL(value, priority);
43 | ds_priority_queue_push(THIS_DS_PRIORITY_QUEUE(), value, priority);
44 | }
45 |
46 | METHOD(pop)
47 | {
48 | PARSE_NONE;
49 | ds_priority_queue_pop(THIS_DS_PRIORITY_QUEUE(), return_value);
50 | }
51 |
52 | METHOD(peek)
53 | {
54 | PARSE_NONE;
55 | RETURN_ZVAL_COPY(ds_priority_queue_peek(THIS_DS_PRIORITY_QUEUE()));
56 | }
57 |
58 | METHOD(isEmpty)
59 | {
60 | PARSE_NONE;
61 | RETURN_BOOL(DS_PRIORITY_QUEUE_IS_EMPTY(THIS_DS_PRIORITY_QUEUE()));
62 | }
63 |
64 | METHOD(toArray)
65 | {
66 | PARSE_NONE;
67 | ds_priority_queue_to_array(THIS_DS_PRIORITY_QUEUE(), return_value);
68 | }
69 |
70 | METHOD(count)
71 | {
72 | PARSE_NONE;
73 | RETURN_LONG(DS_PRIORITY_QUEUE_SIZE(THIS_DS_PRIORITY_QUEUE()));
74 | }
75 |
76 | METHOD(clear)
77 | {
78 | PARSE_NONE;
79 | ds_priority_queue_clear(THIS_DS_PRIORITY_QUEUE());
80 | }
81 |
82 | METHOD(jsonSerialize)
83 | {
84 | PARSE_NONE;
85 | ds_priority_queue_to_array(THIS_DS_PRIORITY_QUEUE(), return_value);
86 | }
87 |
88 | METHOD(getIterator) {
89 | PARSE_NONE;
90 | ZVAL_COPY(return_value, getThis());
91 | }
92 |
93 | void php_ds_register_priority_queue()
94 | {
95 | zend_class_entry ce;
96 |
97 | zend_function_entry methods[] = {
98 | PHP_DS_ME(PriorityQueue, __construct)
99 | PHP_DS_ME(PriorityQueue, allocate)
100 | PHP_DS_ME(PriorityQueue, capacity)
101 | PHP_DS_ME(PriorityQueue, peek)
102 | PHP_DS_ME(PriorityQueue, pop)
103 | PHP_DS_ME(PriorityQueue, push)
104 | PHP_DS_ME(PriorityQueue, getIterator)
105 |
106 | PHP_DS_COLLECTION_ME_LIST(PriorityQueue)
107 | PHP_FE_END
108 | };
109 |
110 | INIT_CLASS_ENTRY(ce, PHP_DS_NS(PriorityQueue), methods);
111 |
112 | php_ds_priority_queue_ce = zend_register_internal_class(&ce);
113 | php_ds_priority_queue_ce->ce_flags |= ZEND_ACC_FINAL;
114 | php_ds_priority_queue_ce->create_object = php_ds_priority_queue_create_object;
115 | php_ds_priority_queue_ce->get_iterator = php_ds_priority_queue_get_iterator;
116 | php_ds_priority_queue_ce->serialize = php_ds_priority_queue_serialize;
117 | php_ds_priority_queue_ce->unserialize = php_ds_priority_queue_unserialize;
118 |
119 | zend_declare_class_constant_long(
120 | php_ds_priority_queue_ce,
121 | STR_AND_LEN("MIN_CAPACITY"),
122 | DS_PRIORITY_QUEUE_MIN_CAPACITY
123 | );
124 |
125 | zend_class_implements(php_ds_priority_queue_ce, 1, collection_ce);
126 | php_ds_register_priority_queue_handlers();
127 | }
128 |
--------------------------------------------------------------------------------
/src/php/classes/php_sequence_ce.h:
--------------------------------------------------------------------------------
1 | #ifndef PHP_DS_SEQUENCE_CE_H
2 | #define PHP_DS_SEQUENCE_CE_H
3 |
4 | #include "php.h"
5 |
6 | extern zend_class_entry *sequence_ce;
7 |
8 | #define PHP_DS_SEQUENCE_ME(cls, name) \
9 | PHP_ME(cls, name, arginfo_Sequence_##name, ZEND_ACC_PUBLIC)
10 |
11 | #define PHP_DS_SEQUENCE_ME_LIST(cls) \
12 | PHP_DS_SEQUENCE_ME(cls, allocate) \
13 | PHP_DS_SEQUENCE_ME(cls, apply) \
14 | PHP_DS_SEQUENCE_ME(cls, capacity) \
15 | PHP_DS_SEQUENCE_ME(cls, contains) \
16 | PHP_DS_SEQUENCE_ME(cls, filter) \
17 | PHP_DS_SEQUENCE_ME(cls, find) \
18 | PHP_DS_SEQUENCE_ME(cls, first) \
19 | PHP_DS_SEQUENCE_ME(cls, get) \
20 | PHP_DS_SEQUENCE_ME(cls, insert) \
21 | PHP_DS_SEQUENCE_ME(cls, join) \
22 | PHP_DS_SEQUENCE_ME(cls, last) \
23 | PHP_DS_SEQUENCE_ME(cls, map) \
24 | PHP_DS_SEQUENCE_ME(cls, merge) \
25 | PHP_DS_SEQUENCE_ME(cls, offsetExists) \
26 | PHP_DS_SEQUENCE_ME(cls, offsetGet) \
27 | PHP_DS_SEQUENCE_ME(cls, offsetSet) \
28 | PHP_DS_SEQUENCE_ME(cls, offsetUnset) \
29 | PHP_DS_SEQUENCE_ME(cls, pop) \
30 | PHP_DS_SEQUENCE_ME(cls, push) \
31 | PHP_DS_SEQUENCE_ME(cls, reduce) \
32 | PHP_DS_SEQUENCE_ME(cls, remove) \
33 | PHP_DS_SEQUENCE_ME(cls, reverse) \
34 | PHP_DS_SEQUENCE_ME(cls, reversed) \
35 | PHP_DS_SEQUENCE_ME(cls, rotate) \
36 | PHP_DS_SEQUENCE_ME(cls, set) \
37 | PHP_DS_SEQUENCE_ME(cls, shift) \
38 | PHP_DS_SEQUENCE_ME(cls, slice) \
39 | PHP_DS_SEQUENCE_ME(cls, sort) \
40 | PHP_DS_SEQUENCE_ME(cls, sorted) \
41 | PHP_DS_SEQUENCE_ME(cls, sum) \
42 | PHP_DS_SEQUENCE_ME(cls, unshift) \
43 |
44 | ARGINFO_LONG( Sequence_allocate, capacity);
45 | ARGINFO_CALLABLE( Sequence_apply, callback);
46 | ARGINFO_NONE_RETURN_LONG( Sequence_capacity);
47 | ARGINFO_VARIADIC_ZVAL_RETURN_BOOL( Sequence_contains, values);
48 | ARGINFO_OPTIONAL_CALLABLE_RETURN_DS( Sequence_filter, callback, Sequence);
49 | ARGINFO_ZVAL( Sequence_find, value);
50 | ARGINFO_NONE( Sequence_first);
51 | ARGINFO_OPTIONAL_STRING_RETURN_STRING( Sequence_join, glue);
52 | ARGINFO_LONG( Sequence_get, index);
53 | ARGINFO_LONG_VARIADIC_ZVAL( Sequence_insert, index, values);
54 | ARGINFO_NONE( Sequence_last);
55 | ARGINFO_CALLABLE_RETURN_DS( Sequence_map, callback, Sequence);
56 | ARGINFO_ZVAL_RETURN_DS( Sequence_merge, values, Sequence);
57 | ARGINFO_ZVAL_RETURN_BOOL( Sequence_offsetExists, offset);
58 | ARGINFO_OFFSET_GET( Sequence_offsetGet);
59 | ARGINFO_OFFSET_SET( Sequence_offsetSet);
60 | ARGINFO_OFFSET_UNSET( Sequence_offsetUnset);
61 | ARGINFO_NONE( Sequence_pop);
62 | ARGINFO_VARIADIC_ZVAL( Sequence_push, values);
63 | ARGINFO_CALLABLE_OPTIONAL_ZVAL( Sequence_reduce, callback, initial);
64 | ARGINFO_LONG( Sequence_remove, index);
65 | ARGINFO_NONE( Sequence_reverse);
66 | ARGINFO_NONE_RETURN_DS( Sequence_reversed, Sequence);
67 | ARGINFO_LONG( Sequence_rotate, rotations);
68 | ARGINFO_LONG_ZVAL( Sequence_set, index, value);
69 | ARGINFO_NONE( Sequence_shift);
70 | ARGINFO_LONG_OPTIONAL_LONG_RETURN_DS( Sequence_slice, index, length, Sequence);
71 | ARGINFO_OPTIONAL_CALLABLE( Sequence_sort, comparator);
72 | ARGINFO_OPTIONAL_CALLABLE_RETURN_DS( Sequence_sorted, comparator, Sequence);
73 | ARGINFO_NONE( Sequence_sum);
74 | ARGINFO_VARIADIC_ZVAL( Sequence_unshift, values);
75 |
76 | void php_ds_register_sequence();
77 |
78 | #endif
79 |
--------------------------------------------------------------------------------
/src/php/handlers/php_queue_handlers.c:
--------------------------------------------------------------------------------
1 | #include "php_common_handlers.h"
2 | #include "php_deque_handlers.h"
3 |
4 | #include "../objects/php_queue.h"
5 | #include "../../ds/ds_queue.h"
6 |
7 | zend_object_handlers php_queue_handlers;
8 |
9 |
10 | static void php_ds_queue_write_dimension
11 | #if PHP_VERSION_ID >= 80000
12 | (zend_object *obj, zval *offset, zval *value) {
13 | ds_queue_t *queue = php_ds_queue_fetch_object(obj)->queue;
14 | #else
15 | (zval *obj, zval *offset, zval *value) {
16 | ds_queue_t *queue = Z_DS_QUEUE_P(obj);
17 | #endif
18 | if (offset == NULL) {
19 | ds_queue_push_one(queue, value);
20 | return;
21 | }
22 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
23 | }
24 |
25 | static void php_ds_queue_free_object(zend_object *object)
26 | {
27 | php_ds_queue_t *queue = php_ds_queue_fetch_object(object);
28 | ds_queue_free(queue->queue);
29 | zend_object_std_dtor(&queue->std);
30 | }
31 |
32 | static int php_ds_queue_count_elements
33 | #if PHP_VERSION_ID >= 80000
34 | (zend_object *obj, zend_long *count) {
35 | ds_queue_t *queue = php_ds_queue_fetch_object(obj)->queue;
36 | #else
37 | (zval *obj, zend_long *count) {
38 | ds_queue_t *queue = Z_DS_QUEUE_P(obj);
39 | #endif
40 | *count = QUEUE_SIZE(queue);
41 | return SUCCESS;
42 | }
43 |
44 | static zend_object *php_ds_queue_clone_obj
45 | #if PHP_VERSION_ID >= 80000
46 | (zend_object *obj) {
47 | ds_queue_t *queue = php_ds_queue_fetch_object(obj)->queue;
48 | #else
49 | (zval *obj) {
50 | ds_queue_t *queue = Z_DS_QUEUE_P(obj);
51 | #endif
52 | return php_ds_queue_create_clone(queue);
53 | }
54 |
55 | static HashTable *php_ds_queue_get_debug_info
56 | #if PHP_VERSION_ID >= 80000
57 | (zend_object *obj, int *is_temp) {
58 | ds_queue_t *queue = php_ds_queue_fetch_object(obj)->queue;
59 | #else
60 | (zval *obj, int *is_temp) {
61 | ds_queue_t *queue = Z_DS_QUEUE_P(obj);
62 | #endif
63 | zval arr;
64 | *is_temp = 1;
65 | ds_queue_to_array(queue, &arr);
66 | return Z_ARRVAL(arr);
67 | }
68 |
69 | static HashTable *php_ds_queue_get_gc
70 | #if PHP_VERSION_ID >= 80000
71 | (zend_object *obj, zval **gc_data, int *gc_count) {
72 | ds_queue_t *queue = php_ds_queue_fetch_object(obj)->queue;
73 | #else
74 | (zval *obj, zval **gc_data, int *gc_count) {
75 | ds_queue_t *queue = Z_DS_QUEUE_P(obj);
76 | #endif
77 | ds_deque_t *deque = queue->deque;
78 |
79 | *gc_data = deque->buffer;
80 | *gc_count = deque->head == 0 ? deque->size : deque->capacity;
81 | return NULL;
82 | }
83 |
84 | void php_ds_register_queue_handlers()
85 | {
86 | memcpy(&php_queue_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
87 |
88 | php_queue_handlers.offset = XtOffsetOf(php_ds_queue_t, std);
89 |
90 | php_queue_handlers.dtor_obj = zend_objects_destroy_object;
91 | php_queue_handlers.get_gc = php_ds_queue_get_gc;
92 | php_queue_handlers.free_obj = php_ds_queue_free_object;
93 | php_queue_handlers.clone_obj = php_ds_queue_clone_obj;
94 | php_queue_handlers.cast_object = php_ds_default_cast_object;
95 | php_queue_handlers.get_debug_info = php_ds_queue_get_debug_info;
96 | php_queue_handlers.count_elements = php_ds_queue_count_elements;
97 | php_queue_handlers.write_dimension = php_ds_queue_write_dimension;
98 | php_queue_handlers.read_dimension = php_ds_read_dimension_by_key_not_supported;
99 | php_queue_handlers.unset_dimension = php_ds_unset_dimension_by_key_not_supported;
100 | php_queue_handlers.has_dimension = php_ds_has_dimension_by_key_not_supported;
101 | }
102 |
--------------------------------------------------------------------------------
/src/php/handlers/php_stack_handlers.c:
--------------------------------------------------------------------------------
1 | #include "php_stack_handlers.h"
2 | #include "php_common_handlers.h"
3 | #include "../../ds/ds_stack.h"
4 | #include "../objects/php_stack.h"
5 |
6 | zend_object_handlers php_ds_stack_handlers;
7 |
8 | static void php_ds_stack_write_dimension
9 | #if PHP_VERSION_ID >= 80000
10 | (zend_object *obj, zval *offset, zval *value) {
11 | ds_stack_t *stack = php_ds_stack_fetch_object(obj)->stack;
12 | #else
13 | (zval *obj, zval *offset, zval *value) {
14 | ds_stack_t *stack = Z_DS_STACK_P(obj);
15 | #endif
16 | if (offset == NULL) {
17 | ds_stack_push(stack, value);
18 | return;
19 | }
20 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
21 | }
22 |
23 | static void php_ds_stack_free_object(zend_object *object)
24 | {
25 | php_ds_stack_t *obj = php_ds_stack_fetch_object(object);
26 | if (obj->stack) {
27 | ds_stack_free(obj->stack);
28 | obj->stack = NULL;
29 | }
30 | zend_object_std_dtor(&obj->std);
31 | }
32 |
33 | static int php_ds_stack_count_elements
34 | #if PHP_VERSION_ID >= 80000
35 | (zend_object *obj, zend_long *count) {
36 | ds_stack_t *stack = php_ds_stack_fetch_object(obj)->stack;
37 | #else
38 | (zval *obj, zend_long *count) {
39 | ds_stack_t *stack = Z_DS_STACK_P(obj);
40 | #endif
41 | *count = DS_STACK_SIZE(stack);
42 | return SUCCESS;
43 | }
44 |
45 | static zend_object *php_ds_stack_clone_obj
46 | #if PHP_VERSION_ID >= 80000
47 | (zend_object *obj) {
48 | ds_stack_t *stack = php_ds_stack_fetch_object(obj)->stack;
49 | #else
50 | (zval *obj) {
51 | ds_stack_t *stack = Z_DS_STACK_P(obj);
52 | #endif
53 | return php_ds_stack_create_clone(stack);
54 | }
55 |
56 | static HashTable *php_ds_stack_get_debug_info
57 | #if PHP_VERSION_ID >= 80000
58 | (zend_object *obj, int *is_temp) {
59 | ds_stack_t *stack = php_ds_stack_fetch_object(obj)->stack;
60 | #else
61 | (zval *obj, int *is_temp) {
62 | ds_stack_t *stack = Z_DS_STACK_P(obj);
63 | #endif
64 | zval arr;
65 | *is_temp = 1;
66 |
67 | ds_stack_to_array(stack, &arr);
68 | return Z_ARRVAL(arr);
69 | }
70 |
71 | static HashTable *php_ds_stack_get_gc
72 | #if PHP_VERSION_ID >= 80000
73 | (zend_object *obj, zval **gc_data, int *gc_count) {
74 | ds_stack_t *stack = php_ds_stack_fetch_object(obj)->stack;
75 | #else
76 | (zval *obj, zval **gc_data, int *gc_count) {
77 | ds_stack_t *stack = Z_DS_STACK_P(obj);
78 | #endif
79 | *gc_data = (zval*) stack->vector->buffer;
80 | *gc_count = (int) stack->vector->size;
81 | return NULL;
82 | }
83 |
84 | void php_register_ds_stack_handlers()
85 | {
86 | memcpy(&php_ds_stack_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
87 |
88 | php_ds_stack_handlers.offset = XtOffsetOf(php_ds_stack_t, std);
89 |
90 | php_ds_stack_handlers.dtor_obj = zend_objects_destroy_object;
91 | php_ds_stack_handlers.get_gc = php_ds_stack_get_gc;
92 | php_ds_stack_handlers.free_obj = php_ds_stack_free_object;
93 | php_ds_stack_handlers.clone_obj = php_ds_stack_clone_obj;
94 | php_ds_stack_handlers.cast_object = php_ds_default_cast_object;
95 | php_ds_stack_handlers.get_debug_info = php_ds_stack_get_debug_info;
96 | php_ds_stack_handlers.count_elements = php_ds_stack_count_elements;
97 | php_ds_stack_handlers.write_dimension = php_ds_stack_write_dimension;
98 | php_ds_stack_handlers.read_dimension = php_ds_read_dimension_by_key_not_supported;
99 | php_ds_stack_handlers.unset_dimension = php_ds_unset_dimension_by_key_not_supported;
100 | php_ds_stack_handlers.has_dimension = php_ds_has_dimension_by_key_not_supported;
101 | }
102 |
--------------------------------------------------------------------------------
/src/ds/ds_deque.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_DEQUE_H
2 | #define DS_DEQUE_H
3 |
4 | #include "../common.h"
5 |
6 | #define DS_DEQUE_MIN_CAPACITY 8 // Must be a power of 2
7 |
8 | #define DS_DEQUE_SIZE(d) ((d)->size)
9 | #define DS_DEQUE_IS_EMPTY(d) ((d)->size == 0)
10 |
11 | #define DS_DEQUE_FOREACH(d, v) \
12 | do { \
13 | const ds_deque_t *_deque = d; \
14 | const zend_long _mask = _deque->capacity - 1; \
15 | const zend_long _size = _deque->size; \
16 | const zend_long _head = _deque->head; \
17 | \
18 | zend_long _i; \
19 | for (_i = 0; _i < _size; _i++) { \
20 | v = &_deque->buffer[(_head + _i) & _mask];
21 |
22 | #define DS_DEQUE_FOREACH_END() \
23 | } \
24 | } while (0)
25 |
26 | typedef struct _ds_deque_t {
27 | zval *buffer;
28 | zend_long capacity;
29 | zend_long head;
30 | zend_long tail;
31 | zend_long size;
32 | } ds_deque_t;
33 |
34 | ds_deque_t *ds_deque();
35 | ds_deque_t *ds_deque_ex(zend_long capacity);
36 | ds_deque_t *ds_deque_clone(ds_deque_t *src);
37 |
38 | void ds_deque_clear(ds_deque_t *deque);
39 | void ds_deque_free(ds_deque_t *deque);
40 | void ds_deque_allocate(ds_deque_t *deque, zend_long capacity);
41 | void ds_deque_reset_head(ds_deque_t *deque);
42 |
43 | void ds_deque_push(ds_deque_t *deque, zval *value);
44 | void ds_deque_push_va(ds_deque_t *deque, VA_PARAMS);
45 | void ds_deque_push_all(ds_deque_t *deque, zval *values);
46 |
47 | void ds_deque_set(ds_deque_t *deque, zend_long index, zval *value);
48 | void ds_deque_pop(ds_deque_t *deque, zval *return_value);
49 | void ds_deque_pop_throw(ds_deque_t *deque, zval *return_value);
50 | void ds_deque_shift(ds_deque_t *deque, zval *return_value);
51 | void ds_deque_shift_throw(ds_deque_t *deque, zval *return_value);
52 | void ds_deque_find(ds_deque_t *deque, zval *value, zval *return_value);
53 | void ds_deque_remove(ds_deque_t *deque, zend_long index, zval *return_value);
54 | void ds_deque_insert_va(ds_deque_t *deque, zend_long index, VA_PARAMS);
55 | void ds_deque_unshift_va(ds_deque_t *deque, VA_PARAMS);
56 |
57 | zval *ds_deque_get(ds_deque_t *deque, zend_long index);
58 | zval *ds_deque_get_last(ds_deque_t *deque);
59 | zval *ds_deque_get_last_throw(ds_deque_t *deque);
60 | zval *ds_deque_get_first(ds_deque_t *deque);
61 | zval *ds_deque_get_first_throw(ds_deque_t *deque);
62 |
63 | bool ds_deque_contains_va(ds_deque_t *deque, VA_PARAMS);
64 | bool ds_deque_isset(ds_deque_t *deque, zend_long index, int check_empty);
65 | bool ds_deque_index_exists(ds_deque_t *deque, zend_long index);
66 |
67 | ds_deque_t *ds_deque_map(ds_deque_t *deque, FCI_PARAMS);
68 | ds_deque_t *ds_deque_filter(ds_deque_t *deque);
69 | ds_deque_t *ds_deque_filter_callback(ds_deque_t *deque, FCI_PARAMS);
70 | ds_deque_t *ds_deque_slice(ds_deque_t *deque, zend_long index, zend_long length);
71 | ds_deque_t *ds_deque_merge(ds_deque_t *deque, zval *values);
72 | ds_deque_t *ds_deque_reversed(ds_deque_t *deque);
73 |
74 | void ds_deque_join(ds_deque_t *deque, char *str, size_t len, zval *return_value);
75 | void ds_deque_reduce(ds_deque_t *deque, zval *initial, zval *return_value, FCI_PARAMS);
76 | void ds_deque_rotate(ds_deque_t *deque, zend_long rotations);
77 | void ds_deque_sort_callback(ds_deque_t *deque);
78 | void ds_deque_sort(ds_deque_t *deque);
79 | void ds_deque_reverse(ds_deque_t *deque);
80 | void ds_deque_to_array(ds_deque_t *deque, zval *return_value);
81 | void ds_deque_apply(ds_deque_t *deque, FCI_PARAMS);
82 | void ds_deque_sum(ds_deque_t *deque, zval *return_value);
83 |
84 | #endif
85 |
--------------------------------------------------------------------------------
/src/php/objects/php_priority_queue.c:
--------------------------------------------------------------------------------
1 | #include "../iterators/php_priority_queue_iterator.h"
2 | #include "../handlers/php_priority_queue_handlers.h"
3 | #include "../classes/php_priority_queue_ce.h"
4 |
5 | #include "php_priority_queue.h"
6 |
7 | zend_object *php_ds_priority_queue_create_object_ex(ds_priority_queue_t *queue)
8 | {
9 | #if PHP_VERSION_ID < 70300
10 | php_ds_priority_queue_t *obj = ecalloc(1, sizeof(php_ds_priority_queue_t) + zend_object_properties_size(php_ds_priority_queue_ce));
11 | #else
12 | php_ds_priority_queue_t *obj = zend_object_alloc(sizeof(php_ds_priority_queue_t), php_ds_priority_queue_ce);
13 | #endif
14 | zend_object_std_init(&obj->std, php_ds_priority_queue_ce);
15 | obj->std.handlers = &php_priority_queue_handlers;
16 |
17 | obj->queue = queue;
18 | obj->gc_data = NULL;
19 | obj->gc_size = 0;
20 |
21 | return &obj->std;
22 | }
23 |
24 | zend_object *php_ds_priority_queue_create_object(zend_class_entry *ce)
25 | {
26 | return php_ds_priority_queue_create_object_ex(ds_priority_queue());
27 | }
28 |
29 |
30 | zend_object *php_ds_priority_queue_create_clone(ds_priority_queue_t *queue)
31 | {
32 | return php_ds_priority_queue_create_object_ex(ds_priority_queue_clone(queue));
33 | }
34 |
35 |
36 | int php_ds_priority_queue_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data)
37 | {
38 | ds_priority_queue_t *queue = Z_DS_PRIORITY_QUEUE_P(object);
39 |
40 | php_serialize_data_t serialize_data = (php_serialize_data_t) data;
41 | PHP_VAR_SERIALIZE_INIT(serialize_data);
42 |
43 | if (queue->size == 0) {
44 | SERIALIZE_SET_ZSTR(ZSTR_EMPTY_ALLOC());
45 |
46 | } else {
47 | ds_priority_queue_node_t *nodes = ds_priority_queue_create_sorted_buffer(queue);
48 | ds_priority_queue_node_t *pos = nodes;
49 | ds_priority_queue_node_t *end = nodes + queue->size;
50 |
51 | smart_str buf = {0};
52 |
53 | for (; pos < end; ++pos) {
54 | php_var_serialize(&buf, &pos->value, &serialize_data);
55 | php_var_serialize(&buf, &pos->priority, &serialize_data);
56 | }
57 |
58 | smart_str_0(&buf);
59 | SERIALIZE_SET_ZSTR(buf.s);
60 | zend_string_release(buf.s);
61 |
62 | efree(nodes);
63 | }
64 |
65 | PHP_VAR_SERIALIZE_DESTROY(serialize_data);
66 | return SUCCESS;
67 | }
68 |
69 | int php_ds_priority_queue_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data)
70 | {
71 | ds_priority_queue_t *queue = ds_priority_queue();
72 |
73 | php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data;
74 |
75 | const unsigned char *pos = buffer;
76 | const unsigned char *end = buffer + length;
77 |
78 | PHP_VAR_UNSERIALIZE_INIT(unserialize_data);
79 | ZVAL_DS_PRIORITY_QUEUE(object, queue);
80 |
81 | while (pos != end) {
82 | zval *value, *priority;
83 |
84 | value = var_tmp_var(&unserialize_data);
85 | if ( ! php_var_unserialize(value, &pos, end, &unserialize_data)) {
86 | goto error;
87 | }
88 |
89 | priority = var_tmp_var(&unserialize_data);
90 |
91 | if ( ! php_var_unserialize(priority, &pos, end, &unserialize_data)) {
92 | goto error;
93 | }
94 |
95 | ds_priority_queue_push(queue, value, priority);
96 | }
97 |
98 | PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
99 | return SUCCESS;
100 |
101 | error:
102 | ds_priority_queue_free(queue);
103 | PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
104 | UNSERIALIZE_ERROR();
105 | return FAILURE;
106 | }
107 |
--------------------------------------------------------------------------------
/config.m4:
--------------------------------------------------------------------------------
1 | PHP_ARG_ENABLE(ds, whether to enable ds support,
2 | [ --enable-ds Enable ds support])
3 |
4 | if test "$PHP_DS" != "no"; then
5 | PHP_NEW_EXTENSION(ds, \
6 | \
7 | src/common.c \
8 | \
9 | dnl Internal
10 | src/ds/ds_vector.c \
11 | src/ds/ds_deque.c \
12 | src/ds/ds_htable.c \
13 | src/ds/ds_set.c \
14 | src/ds/ds_map.c \
15 | src/ds/ds_stack.c \
16 | src/ds/ds_priority_queue.c \
17 | src/ds/ds_queue.c \
18 | \
19 | src/php/objects/php_vector.c \
20 | src/php/objects/php_deque.c \
21 | src/php/objects/php_map.c \
22 | src/php/objects/php_pair.c \
23 | src/php/objects/php_priority_queue.c \
24 | src/php/objects/php_queue.c \
25 | src/php/objects/php_set.c \
26 | src/php/objects/php_stack.c \
27 | \
28 | dnl Iterators
29 | src/php/iterators/php_vector_iterator.c \
30 | src/php/iterators/php_deque_iterator.c \
31 | src/php/iterators/php_set_iterator.c \
32 | src/php/iterators/php_map_iterator.c \
33 | src/php/iterators/php_stack_iterator.c \
34 | src/php/iterators/php_htable_iterator.c \
35 | src/php/iterators/php_priority_queue_iterator.c \
36 | src/php/iterators/php_queue_iterator.c \
37 | \
38 | dnl Handlers
39 | src/php/handlers/php_common_handlers.c \
40 | src/php/handlers/php_vector_handlers.c \
41 | src/php/handlers/php_deque_handlers.c \
42 | src/php/handlers/php_set_handlers.c \
43 | src/php/handlers/php_map_handlers.c \
44 | src/php/handlers/php_stack_handlers.c \
45 | src/php/handlers/php_pair_handlers.c \
46 | src/php/handlers/php_priority_queue_handlers.c \
47 | src/php/handlers/php_queue_handlers.c \
48 | \
49 | dnl Interfaces
50 | src/php/classes/php_hashable_ce.c \
51 | src/php/classes/php_collection_ce.c \
52 | src/php/classes/php_sequence_ce.c \
53 | \
54 | dnl Classes
55 | src/php/classes/php_vector_ce.c \
56 | src/php/classes/php_deque_ce.c \
57 | src/php/classes/php_set_ce.c \
58 | src/php/classes/php_map_ce.c \
59 | src/php/classes/php_stack_ce.c \
60 | src/php/classes/php_pair_ce.c \
61 | src/php/classes/php_priority_queue_ce.c \
62 | src/php/classes/php_queue_ce.c \
63 | \
64 | php_ds.c \
65 | \
66 | , $ext_shared, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
67 |
68 | PHP_ADD_BUILD_DIR($ext_builddir/src, 1)
69 | PHP_ADD_BUILD_DIR($ext_builddir/src/ds, 1)
70 | PHP_ADD_BUILD_DIR($ext_builddir/src/php, 1)
71 | PHP_ADD_BUILD_DIR($ext_builddir/src/php/objects, 1)
72 | PHP_ADD_BUILD_DIR($ext_builddir/src/php/classes, 1)
73 | PHP_ADD_BUILD_DIR($ext_builddir/src/php/iterators, 1)
74 | PHP_ADD_BUILD_DIR($ext_builddir/src/php/handlers, 1)
75 |
76 | PHP_ADD_EXTENSION_DEP(ds, spl)
77 | PHP_ADD_EXTENSION_DEP(ds, json)
78 | fi
79 |
80 |
81 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file.
3 |
4 | ## [1.6.0] - 2025-05-02
5 | ### Added
6 | - Support for PHP 8.4 @simPod
7 |
8 | ## [1.5.0] - 2023-12-19
9 | ### Fixed
10 | - Support for PHP 8.3
11 | - Fix #194 @nielsdos
12 | - Fix #200 @nielsdos
13 |
14 | ## [1.4.0] - 2021-12-13
15 | ### Fixed
16 | - ArrayAccess implemented consistently
17 | - IteratorAggregate implemented consistently
18 | - A few incorrect return types
19 |
20 | ## [1.3.0] - 2020-10-13
21 | ### Fixed
22 | - ArrayAccess implemented consistently
23 | - IteratorAggregate implemented consistently
24 | - A few incorrect return types
25 |
26 | ## [1.2.9] - 2019-05-11
27 | ### Fixed
28 | - Segfault when iterating an implicit instance of Stack, Queue or PriorityQueue
29 |
30 | ## [1.2.8] - 2019-01-24
31 | ### Fixed
32 | - Fixed buffer outflow during deserialization of map objects. #132 @rado-h
33 |
34 | ## [1.2.7] - 2018-11-18
35 | ### Fixed
36 | - Fixed pair reflection bugs. #119
37 |
38 | ## [1.2.6] - 2018-05-24
39 | ### Fixed
40 | - Fixed not clearing memory after buffer reallocation. #114
41 |
42 | ## [1.2.5] - 2018-03-13
43 | ### Fixed
44 | - Buffer outflow during deserialization of objects. #111
45 |
46 | ## [1.2.4] - 2017-11-29
47 | ### Fixed
48 | - Empty `PriorityQueue` causing segfault on `gc_collect_cycles`. #106
49 |
50 | ## [1.2.3] - 2017-08-16
51 | ### Fixed
52 | - Memory allocation bug on ppc64. @remicollet #88
53 |
54 | ## [1.2.2] - 2017-08-08
55 | ### Fixed
56 | - Segfault in ds_htable_lookup_bucket_by_hash. @gnoddep #86
57 |
58 | ## [1.2.1] - 2017-08-03
59 | ### Changed
60 | - Minor capacity adjustments.
61 |
62 | ## [1.2.0] - 2017-07-22
63 | ### Changed
64 | - Vector's minimum and default capacity down from 10 to 8.
65 | - Map and Set's minimum and default capacity down from 16 to 8.
66 | - Hash function of arrays is now the length of the array, so O(1).
67 |
68 | ## [1.1.10] - 2017-06-22
69 | ### Fixed
70 | - Using a key as reference not working correctly with array access. #86
71 |
72 | ## [1.1.9] - 2017-04-26
73 | ### Fixed
74 | - Iterating over an implicit iterator (not variable). #82
75 |
76 | ## [1.1.8] - 2017-03-24
77 | ### Fixed
78 | - PriorityQueue automatic truncate bug. #78
79 | - Bugs related to unserialization. #77
80 |
81 | ## [1.1.7] - 2017-02-11
82 | ### Fixed
83 | - Preliminary support for PHP 7.2
84 |
85 | ## [1.1.6] - 2016-09-03
86 | ### Fixed
87 | - `Map` truncating to capacity less than the minimum.
88 |
89 | ## [1.1.5] - 2016-09-01
90 | ### Fixed
91 | - `phpinfo` header
92 | - `ds_htable_put_distinct` wasn't rehashing the correct bucket pointer (Fixes #53)
93 | - Memory leaks.
94 |
95 | ## [1.1.4] - 2016-08-09
96 | ### Fixed
97 | - `Vector` and `Deque` rotate crashing when empty (mod zero).
98 |
99 | ## [1.1.3] - 2016-08-08
100 | ### Fixed
101 | - Memory leaks during map when callback throws an exception.
102 | - Memory leaks when structures contain themselves.
103 | - Module dependencies.
104 |
105 | ## Added
106 | - Version info in `phpinfo()`
107 |
108 | ### Improved
109 | - `Map::map` and `Map::filter` are now slightly faster.
110 |
111 | ## [1.1.2] - 2016-08-05
112 | ### Fixed
113 | - Many, many memory leaks.
114 | - Added memory checks to CI.
115 | - Performance improvements.
116 | - JSON dependency now handled correctly (thanks @nikic).
117 |
118 | ## [1.1.1] - 2016-08-04
119 | ### Fixed
120 | - Multiple memory leaks where objects were not free'd correctly.
121 |
122 | ## [1.1.0] - 2016-08-04
123 | ### Added
124 | - `Pair::copy`
125 |
126 | ## [1.0.4] - 2016-08-01
127 | ### Fixed
128 | - `unserialize` memory leak when failed to unserialize.
129 | - `htable` bucket copy macro didn't copy the bucket's "next".
130 |
131 | ## [1.0.3] - 2016-08-01
132 | ### Added
133 | - `Set::merge`
134 |
135 | ### Fixed
136 | - ds_htable_put_next bucket rehash fix
137 | -
138 | ## [1.0.2] - 2016-07-31
139 | ### Added
140 | - `Map::putAll`
141 |
--------------------------------------------------------------------------------
/src/php/classes/php_stack_ce.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 |
3 | #include "../parameters.h"
4 | #include "../arginfo.h"
5 |
6 | #include "../objects/php_stack.h"
7 |
8 | #include "../iterators/php_stack_iterator.h"
9 | #include "../handlers/php_stack_handlers.h"
10 |
11 | #include "php_collection_ce.h"
12 | #include "php_stack_ce.h"
13 |
14 | #define METHOD(name) PHP_METHOD(Stack, name)
15 |
16 | zend_class_entry *php_ds_stack_ce;
17 |
18 | METHOD(__construct)
19 | {
20 | PARSE_OPTIONAL_ZVAL(values);
21 |
22 | if (values) {
23 | ds_stack_push_all(THIS_DS_STACK(), values);
24 | }
25 | }
26 |
27 | METHOD(allocate)
28 | {
29 | PARSE_LONG(capacity);
30 | ds_stack_allocate(THIS_DS_STACK(), capacity);
31 | }
32 |
33 | METHOD(capacity)
34 | {
35 | PARSE_NONE;
36 | RETURN_LONG(DS_STACK_CAPACITY(THIS_DS_STACK()));
37 | }
38 |
39 | METHOD(push)
40 | {
41 | PARSE_VARIADIC_ZVAL();
42 | ds_stack_push_va(THIS_DS_STACK(), argc, argv);
43 | }
44 |
45 | METHOD(pop)
46 | {
47 | PARSE_NONE;
48 | ds_stack_pop_throw(THIS_DS_STACK(), return_value);
49 | }
50 |
51 | METHOD(peek)
52 | {
53 | PARSE_NONE;
54 | RETURN_ZVAL_COPY(ds_stack_peek_throw(THIS_DS_STACK()));
55 | }
56 |
57 | METHOD(count)
58 | {
59 | PARSE_NONE;
60 | RETURN_LONG(DS_STACK_SIZE(THIS_DS_STACK()));
61 | }
62 |
63 | METHOD(copy)
64 | {
65 | PARSE_NONE;
66 | RETURN_OBJ(php_ds_stack_create_clone(THIS_DS_STACK()));
67 | }
68 |
69 | METHOD(clear)
70 | {
71 | PARSE_NONE;
72 | ds_stack_clear(THIS_DS_STACK());
73 | }
74 |
75 | METHOD(toArray)
76 | {
77 | PARSE_NONE;
78 | ds_stack_to_array(THIS_DS_STACK(), return_value);
79 | }
80 |
81 | METHOD(isEmpty)
82 | {
83 | PARSE_NONE;
84 | RETURN_BOOL(DS_STACK_IS_EMPTY(THIS_DS_STACK()));
85 | }
86 |
87 | METHOD(jsonSerialize)
88 | {
89 | PARSE_NONE;
90 | ds_stack_to_array(THIS_DS_STACK(), return_value);
91 | }
92 |
93 | METHOD(getIterator) {
94 | PARSE_NONE;
95 | ZVAL_COPY(return_value, getThis());
96 | }
97 |
98 | METHOD(offsetExists)
99 | {
100 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
101 | }
102 |
103 | METHOD(offsetGet)
104 | {
105 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
106 | }
107 |
108 | METHOD(offsetSet)
109 | {
110 | ds_stack_t *stack = THIS_DS_STACK();
111 |
112 | PARSE_ZVAL_ZVAL(offset, value);
113 |
114 | if (Z_TYPE_P(offset) == IS_NULL) {
115 | ds_stack_push(stack, value);
116 | } else {
117 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
118 | }
119 | }
120 |
121 | METHOD(offsetUnset)
122 | {
123 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
124 | }
125 |
126 | void php_ds_register_stack()
127 | {
128 | zend_class_entry ce;
129 |
130 | zend_function_entry methods[] = {
131 | PHP_DS_ME(Stack, __construct)
132 | PHP_DS_ME(Stack, allocate)
133 | PHP_DS_ME(Stack, capacity)
134 | PHP_DS_ME(Stack, peek)
135 | PHP_DS_ME(Stack, pop)
136 | PHP_DS_ME(Stack, push)
137 | PHP_DS_ME(Stack, getIterator)
138 |
139 | PHP_DS_ME(Stack, offsetExists)
140 | PHP_DS_ME(Stack, offsetGet)
141 | PHP_DS_ME(Stack, offsetSet)
142 | PHP_DS_ME(Stack, offsetUnset)
143 |
144 | PHP_DS_COLLECTION_ME_LIST(Stack)
145 | PHP_FE_END
146 | };
147 |
148 | INIT_CLASS_ENTRY(ce, PHP_DS_NS(Stack), methods);
149 |
150 | php_ds_stack_ce = zend_register_internal_class(&ce);
151 | php_ds_stack_ce->ce_flags |= ZEND_ACC_FINAL;
152 | php_ds_stack_ce->create_object = php_ds_stack_create_object;
153 | php_ds_stack_ce->get_iterator = php_ds_stack_get_iterator;
154 | php_ds_stack_ce->serialize = php_ds_stack_serialize;
155 | php_ds_stack_ce->unserialize = php_ds_stack_unserialize;
156 |
157 | zend_class_implements(php_ds_stack_ce, 2,
158 | collection_ce,
159 | zend_ce_arrayaccess
160 | );
161 |
162 | php_register_ds_stack_handlers();
163 | }
164 |
--------------------------------------------------------------------------------
/src/php/classes/php_queue_ce.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 |
3 | #include "../parameters.h"
4 | #include "../arginfo.h"
5 |
6 | #include "../iterators/php_queue_iterator.h"
7 | #include "../handlers/php_queue_handlers.h"
8 | #include "../objects/php_queue.h"
9 |
10 | #include "php_collection_ce.h"
11 | #include "php_queue_ce.h"
12 |
13 | #define METHOD(name) PHP_METHOD(Queue, name)
14 |
15 | zend_class_entry *php_ds_queue_ce;
16 |
17 | METHOD(__construct)
18 | {
19 | PARSE_OPTIONAL_ZVAL(values);
20 |
21 | if (values) {
22 | ds_queue_push_all(THIS_DS_QUEUE(), values);
23 | }
24 | }
25 |
26 | METHOD(allocate)
27 | {
28 | PARSE_LONG(capacity);
29 | ds_queue_allocate(THIS_DS_QUEUE(), capacity);
30 | }
31 |
32 | METHOD(capacity)
33 | {
34 | PARSE_NONE;
35 | RETURN_LONG(ds_queue_capacity(THIS_DS_QUEUE()));
36 | }
37 |
38 | METHOD(push)
39 | {
40 | PARSE_VARIADIC_ZVAL();
41 | ds_queue_push(THIS_DS_QUEUE(), argc, argv);
42 | }
43 |
44 | METHOD(pop)
45 | {
46 | PARSE_NONE;
47 | ds_queue_pop_throw(THIS_DS_QUEUE(), return_value);
48 | }
49 |
50 | METHOD(peek)
51 | {
52 | PARSE_NONE;
53 | RETURN_ZVAL_COPY(ds_queue_peek_throw(THIS_DS_QUEUE()));
54 | }
55 |
56 | METHOD(copy)
57 | {
58 | PARSE_NONE;
59 | RETURN_OBJ(php_ds_queue_create_clone(THIS_DS_QUEUE()));
60 | }
61 |
62 | METHOD(count)
63 | {
64 | PARSE_NONE;
65 | RETURN_LONG(QUEUE_SIZE(THIS_DS_QUEUE()));
66 | }
67 |
68 | METHOD(clear)
69 | {
70 | PARSE_NONE;
71 | ds_queue_clear(THIS_DS_QUEUE());
72 | }
73 |
74 | METHOD(toArray)
75 | {
76 | PARSE_NONE;
77 | ds_queue_to_array(THIS_DS_QUEUE(), return_value);
78 | }
79 |
80 | METHOD(isEmpty)
81 | {
82 | PARSE_NONE;
83 | RETURN_BOOL(QUEUE_SIZE(THIS_DS_QUEUE()) == 0);
84 | }
85 |
86 | METHOD(jsonSerialize)
87 | {
88 | PARSE_NONE;
89 | ds_queue_to_array(THIS_DS_QUEUE(), return_value);
90 | }
91 |
92 | METHOD(getIterator) {
93 | PARSE_NONE;
94 | ZVAL_COPY(return_value, getThis());
95 | }
96 |
97 | METHOD(offsetExists)
98 | {
99 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
100 | }
101 |
102 | METHOD(offsetGet)
103 | {
104 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
105 | }
106 |
107 | METHOD(offsetSet)
108 | {
109 | PARSE_ZVAL_ZVAL(offset, value);
110 |
111 | if (Z_TYPE_P(offset) == IS_NULL) {
112 | ds_queue_push(THIS_DS_QUEUE(), 1, value);
113 | } else {
114 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
115 | }
116 | }
117 |
118 | METHOD(offsetUnset)
119 | {
120 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
121 | }
122 |
123 | void php_ds_register_queue()
124 | {
125 | zend_class_entry ce;
126 |
127 | zend_function_entry methods[] = {
128 | PHP_DS_ME(Queue, __construct)
129 | PHP_DS_ME(Queue, allocate)
130 | PHP_DS_ME(Queue, capacity)
131 | PHP_DS_ME(Queue, peek)
132 | PHP_DS_ME(Queue, pop)
133 | PHP_DS_ME(Queue, push)
134 | PHP_DS_ME(Queue, getIterator)
135 |
136 | PHP_DS_ME(Queue, offsetExists)
137 | PHP_DS_ME(Queue, offsetGet)
138 | PHP_DS_ME(Queue, offsetSet)
139 | PHP_DS_ME(Queue, offsetUnset)
140 |
141 | PHP_DS_COLLECTION_ME_LIST(Queue)
142 | PHP_FE_END
143 | };
144 |
145 | INIT_CLASS_ENTRY(ce, PHP_DS_NS(Queue), methods);
146 |
147 | php_ds_queue_ce = zend_register_internal_class(&ce);
148 | php_ds_queue_ce->ce_flags |= ZEND_ACC_FINAL;
149 | php_ds_queue_ce->create_object = php_ds_queue_create_object;
150 | php_ds_queue_ce->get_iterator = php_ds_queue_get_iterator;
151 | php_ds_queue_ce->serialize = php_ds_queue_serialize;
152 | php_ds_queue_ce->unserialize = php_ds_queue_unserialize;
153 |
154 | zend_declare_class_constant_long(php_ds_queue_ce, STR_AND_LEN("MIN_CAPACITY"), DS_DEQUE_MIN_CAPACITY);
155 |
156 | zend_class_implements(php_ds_queue_ce, 2,
157 | collection_ce,
158 | zend_ce_arrayaccess
159 | );
160 |
161 | php_ds_register_queue_handlers();
162 | }
163 |
--------------------------------------------------------------------------------
/src/php/handlers/php_set_handlers.c:
--------------------------------------------------------------------------------
1 | #include "php_common_handlers.h"
2 | #include "php_set_handlers.h"
3 | #include "../../ds/ds_set.h"
4 | #include "../objects/php_set.h"
5 | #include "../classes/php_set_ce.h"
6 |
7 | zend_object_handlers php_ds_set_handlers;
8 |
9 | static zval *php_ds_set_read_dimension
10 | #if PHP_VERSION_ID >= 80000
11 | (zend_object *obj, zval *offset, int type, zval *rv) {
12 | ds_set_t *set = php_ds_set_fetch_object(obj)->set;
13 | #else
14 | (zval *obj, zval *offset, int type, zval *rv) {
15 | ds_set_t *set = Z_DS_SET_P(obj);
16 | #endif
17 | if (Z_TYPE_P(offset) != IS_LONG) {
18 | INTEGER_INDEX_REQUIRED(offset);
19 | return NULL;
20 | }
21 |
22 | // Only support read, not write.
23 | if (type != BP_VAR_R && type != BP_VAR_IS) {
24 | return &EG(uninitialized_zval);
25 | }
26 |
27 | return ds_set_get(set, Z_LVAL_P(offset));
28 | }
29 |
30 | static void php_ds_set_write_dimension
31 | #if PHP_VERSION_ID >= 80000
32 | (zend_object *obj, zval *offset, zval *value) {
33 | ds_set_t *set = php_ds_set_fetch_object(obj)->set;
34 | #else
35 | (zval *obj, zval *offset, zval *value) {
36 | ds_set_t *set = Z_DS_SET_P(obj);
37 | #endif
38 | if (offset == NULL) {
39 | ds_set_add(set, value);
40 | return;
41 | }
42 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
43 | }
44 |
45 | static int php_ds_set_count_elements
46 | #if PHP_VERSION_ID >= 80000
47 | (zend_object *obj, zend_long *count) {
48 | ds_set_t *set = php_ds_set_fetch_object(obj)->set;
49 | #else
50 | (zval *obj, zend_long *count) {
51 | ds_set_t *set = Z_DS_SET_P(obj);
52 | #endif
53 | *count = DS_SET_SIZE(set);
54 | return SUCCESS;
55 | }
56 |
57 | static void php_ds_set_free_object(zend_object *object)
58 | {
59 | php_ds_set_t *obj = php_ds_set_fetch_object(object);
60 | ds_set_free(obj->set);
61 | zend_object_std_dtor(&obj->std);
62 | }
63 |
64 | static HashTable *php_ds_set_get_debug_info
65 | #if PHP_VERSION_ID >= 80000
66 | (zend_object *obj, int *is_temp) {
67 | ds_set_t *set = php_ds_set_fetch_object(obj)->set;
68 | #else
69 | (zval *obj, int *is_temp) {
70 | ds_set_t *set = Z_DS_SET_P(obj);
71 | #endif
72 | zval arr;
73 | *is_temp = 1;
74 |
75 | ds_set_to_array(set, &arr);
76 | return Z_ARRVAL(arr);
77 | }
78 |
79 | static zend_object *php_ds_set_clone_obj
80 | #if PHP_VERSION_ID >= 80000
81 | (zend_object *obj) {
82 | ds_set_t *set = php_ds_set_fetch_object(obj)->set;
83 | #else
84 | (zval *obj) {
85 | ds_set_t *set = Z_DS_SET_P(obj);
86 | #endif
87 | return php_ds_set_create_clone(set);
88 | }
89 |
90 | static HashTable *php_ds_set_get_gc
91 | #if PHP_VERSION_ID >= 80000
92 | (zend_object *obj, zval **gc_data, int *gc_count) {
93 | ds_set_t *set = php_ds_set_fetch_object(obj)->set;
94 | #else
95 | (zval *obj, zval **gc_data, int *gc_count) {
96 | ds_set_t *set = Z_DS_SET_P(obj);
97 | #endif
98 | if (DS_SET_IS_EMPTY(set)) {
99 | *gc_data = NULL;
100 | *gc_count = 0;
101 |
102 | } else {
103 | *gc_data = (zval*) set->table->buckets;
104 | *gc_count = (int) set->table->next * 2;
105 | }
106 | return NULL;
107 | }
108 |
109 | void php_ds_register_set_handlers()
110 | {
111 | memcpy(&php_ds_set_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
112 |
113 | php_ds_set_handlers.offset = XtOffsetOf(php_ds_set_t, std);
114 |
115 | php_ds_set_handlers.cast_object = php_ds_default_cast_object;
116 | php_ds_set_handlers.clone_obj = php_ds_set_clone_obj;
117 | php_ds_set_handlers.count_elements = php_ds_set_count_elements;
118 | php_ds_set_handlers.free_obj = php_ds_set_free_object;
119 | php_ds_set_handlers.get_debug_info = php_ds_set_get_debug_info;
120 | php_ds_set_handlers.get_gc = php_ds_set_get_gc;
121 | php_ds_set_handlers.read_dimension = php_ds_set_read_dimension;
122 | php_ds_set_handlers.write_dimension = php_ds_set_write_dimension;
123 | php_ds_set_handlers.unset_dimension = php_ds_unset_dimension_by_key_not_supported;
124 | php_ds_set_handlers.has_dimension = php_ds_has_dimension_by_key_not_supported;
125 | }
126 |
--------------------------------------------------------------------------------
/src/ds/ds_vector.h:
--------------------------------------------------------------------------------
1 | #ifndef DS_VECTOR_H
2 | #define DS_VECTOR_H
3 |
4 | #include "../common.h"
5 |
6 | typedef struct ds_vector {
7 | zval *buffer;
8 | zend_long capacity; // Buffer length
9 | zend_long size; // Number of values in the buffer
10 | } ds_vector_t;
11 |
12 | #define DS_VECTOR_MIN_CAPACITY 8 // Does not have to be a power of 2
13 |
14 | #define DS_VECTOR_SIZE(v) ((v)->size)
15 | #define DS_VECTOR_IS_EMPTY(v) (DS_VECTOR_SIZE(v) == 0)
16 |
17 | /**
18 | * Foreach value
19 | */
20 | #define DS_VECTOR_FOREACH(v, z) \
21 | do { \
22 | zval *x = v->buffer; \
23 | zval *y = x + v->size; \
24 | for (; x < y; ++x) { \
25 | z = x;
26 |
27 | /**
28 | * Foreach value from back to front
29 | */
30 | #define DS_VECTOR_FOREACH_REVERSED(v, z) \
31 | do { \
32 | zval *y = v->buffer; \
33 | zval *x = y + v->size - 1; \
34 | for (; x >= y; --x) { \
35 | z = x;
36 |
37 | /**
38 | * Call this after DS_VECTOR_FOREACH*
39 | */
40 | #define DS_VECTOR_FOREACH_END() \
41 | } \
42 | } while (0)
43 |
44 | ds_vector_t *ds_vector_clone(ds_vector_t *src);
45 | ds_vector_t *ds_vector();
46 | ds_vector_t *ds_vector_ex(zend_long capacity);
47 | ds_vector_t *ds_vector_from_buffer(zval *buffer, zend_long capacity, zend_long size);
48 |
49 | void ds_vector_allocate(ds_vector_t *vector, zend_long capacity);
50 |
51 | void ds_vector_clear(ds_vector_t *vector);
52 | void ds_vector_free(ds_vector_t *vector);
53 |
54 | void ds_vector_set(ds_vector_t *vector, zend_long index, zval *value);
55 | void ds_vector_pop(ds_vector_t *vector, zval *return_value);
56 | void ds_vector_pop_throw(ds_vector_t *vector, zval *return_value);
57 | void ds_vector_shift(ds_vector_t *vector, zval *return_value);
58 | void ds_vector_shift_throw(ds_vector_t *vector, zval *return_value);
59 | void ds_vector_find(ds_vector_t *vector, zval *value, zval *return_value);
60 | void ds_vector_remove(ds_vector_t *vector, zend_long index, zval *return_value);
61 |
62 | void ds_vector_insert(ds_vector_t *vector, zend_long index, zval *value);
63 | void ds_vector_insert_va(ds_vector_t *vector, zend_long index, VA_PARAMS);
64 |
65 | void ds_vector_unshift(ds_vector_t *vector, zval *value);
66 | void ds_vector_unshift_va(ds_vector_t *vector, VA_PARAMS);
67 |
68 | bool ds_vector_contains(ds_vector_t *vector, zval *value);
69 | bool ds_vector_contains_va(ds_vector_t *vector, VA_PARAMS);
70 |
71 | void ds_vector_push(ds_vector_t *vector, zval *value);
72 | void ds_vector_push_va(ds_vector_t *vector, VA_PARAMS);
73 | void ds_vector_push_all(ds_vector_t *vector, zval *values);
74 |
75 | zval *ds_vector_get(ds_vector_t *vector, zend_long index);
76 | zval *ds_vector_get_last(ds_vector_t *vector);
77 | zval *ds_vector_get_first(ds_vector_t *vector);
78 | zval *ds_vector_get_last_throw(ds_vector_t *vector);
79 | zval *ds_vector_get_first_throw(ds_vector_t *vector);
80 |
81 | ds_vector_t *ds_vector_map(ds_vector_t *vector, FCI_PARAMS);
82 | ds_vector_t *ds_vector_slice(ds_vector_t *vector, zend_long index, zend_long length);
83 | ds_vector_t *ds_vector_filter(ds_vector_t *vector);
84 | ds_vector_t *ds_vector_filter_callback(ds_vector_t *vector, FCI_PARAMS);
85 | ds_vector_t *ds_vector_merge(ds_vector_t *vector, zval *values);
86 | ds_vector_t *ds_vector_reversed(ds_vector_t *vector);
87 |
88 | void ds_vector_reduce(ds_vector_t *vector, zval *initial, zval *return_value, FCI_PARAMS);
89 | void ds_vector_reverse(ds_vector_t *vector);
90 | void ds_vector_rotate(ds_vector_t *vector, zend_long rotations);
91 | void ds_vector_join(ds_vector_t *vector, char *str, size_t len, zval *return_value);
92 | void ds_vector_apply(ds_vector_t *vector, FCI_PARAMS);
93 |
94 | void ds_vector_sum(ds_vector_t *vector, zval *return_value);
95 |
96 | void ds_vector_sort(ds_vector_t *vector);
97 | void ds_vector_sort_callback(ds_vector_t *vector);
98 |
99 | void ds_vector_to_array(ds_vector_t *vector, zval *return_value);
100 |
101 | bool ds_vector_index_exists(ds_vector_t *vector, zend_long index);
102 | bool ds_vector_isset(ds_vector_t *vector, zend_long index, int check_empty);
103 |
104 | #endif
105 |
--------------------------------------------------------------------------------
/src/php/objects/php_pair.c:
--------------------------------------------------------------------------------
1 | #include "../handlers/php_pair_handlers.h"
2 | #include "../classes/php_pair_ce.h"
3 | #include "php_pair.h"
4 |
5 | zend_object *php_ds_pair_create_object(zend_class_entry *ce)
6 | {
7 | #if PHP_VERSION_ID < 70300
8 | php_ds_pair_t *obj = ecalloc(1, sizeof(php_ds_pair_t) + zend_object_properties_size(ce));
9 | #else
10 | php_ds_pair_t *obj = zend_object_alloc(sizeof(php_ds_pair_t), ce);
11 | #endif
12 | zend_object_std_init(&obj->std, ce);
13 | object_properties_init(&obj->std, ce);
14 | obj->std.handlers = &php_pair_handlers;
15 |
16 | return &obj->std;
17 | }
18 |
19 | php_ds_pair_t *php_ds_pair()
20 | {
21 | return (php_ds_pair_t*) php_ds_pair_create_object(php_ds_pair_ce);
22 | }
23 |
24 | php_ds_pair_t *php_ds_pair_ex(zval *key, zval *value)
25 | {
26 | php_ds_pair_t *obj = php_ds_pair();
27 |
28 | php_ds_pair_set_key(obj, key);
29 | php_ds_pair_set_value(obj, value);
30 |
31 | return obj;
32 | }
33 |
34 | zend_object *php_ds_pair_create_clone(php_ds_pair_t *obj)
35 | {
36 | zval *key = php_ds_pair_get_key(obj);
37 | zval *val = php_ds_pair_get_value(obj);
38 |
39 | return (zend_object *) php_ds_pair_ex(key, val);
40 | }
41 |
42 | void php_ds_pair_set_key(php_ds_pair_t *pair, zval *key)
43 | {
44 | #if PHP_VERSION_ID >= 80000
45 | zend_update_property(php_ds_pair_ce, (zend_object*) pair, STR_AND_LEN("key"), key);
46 | #else
47 | zval tmp;
48 | ZVAL_DS_PAIR(&tmp, pair);
49 | zend_update_property(php_ds_pair_ce, &tmp, STR_AND_LEN("key"), key);
50 | #endif
51 | }
52 |
53 | void php_ds_pair_set_value(php_ds_pair_t *pair, zval *value)
54 | {
55 | #if PHP_VERSION_ID >= 80000
56 | zend_update_property(php_ds_pair_ce, (zend_object*) pair, STR_AND_LEN("value"), value);
57 | #else
58 | zval tmp;
59 | ZVAL_DS_PAIR(&tmp, pair);
60 | zend_update_property(php_ds_pair_ce, &tmp, STR_AND_LEN("value"), value);
61 | #endif
62 | }
63 |
64 | zval *php_ds_pair_get_key(php_ds_pair_t *pair)
65 | {
66 | zval rv;
67 | #if PHP_VERSION_ID >= 80000
68 | return zend_read_property(php_ds_pair_ce, (zend_object*) pair, STR_AND_LEN("key"), false, &rv);
69 | #else
70 | zval tmp;
71 | ZVAL_DS_PAIR(&tmp, pair);
72 | return zend_read_property(php_ds_pair_ce, &tmp, STR_AND_LEN("key"), false, &rv);
73 | #endif
74 | }
75 |
76 | zval *php_ds_pair_get_value(php_ds_pair_t *pair)
77 | {
78 | zval rv;
79 | #if PHP_VERSION_ID >= 80000
80 | return zend_read_property(php_ds_pair_ce, (zend_object*) pair, STR_AND_LEN("value"), false, &rv);
81 | #else
82 | zval tmp;
83 | ZVAL_DS_PAIR(&tmp, pair);
84 | return zend_read_property(php_ds_pair_ce, &tmp, STR_AND_LEN("value"), false, &rv);
85 | #endif
86 | }
87 |
88 | void php_ds_pair_to_array(php_ds_pair_t *obj, zval *result)
89 | {
90 | zval *key = php_ds_pair_get_key(obj);
91 | zval *val = php_ds_pair_get_value(obj);
92 |
93 | array_init_size(result, 2);
94 |
95 | add_assoc_zval(result, "key", key);
96 | add_assoc_zval(result, "value", val);
97 |
98 | Z_TRY_ADDREF_P(key);
99 | Z_TRY_ADDREF_P(val);
100 | }
101 |
102 | int php_ds_pair_serialize(zval *object, unsigned char **buffer, size_t *length, zend_serialize_data *data)
103 | {
104 | zval *key, *val;
105 | smart_str buf = {0};
106 |
107 | php_ds_pair_t *pair = Z_DS_PAIR_P(object);
108 |
109 | php_serialize_data_t serialize_data = (php_serialize_data_t) data;
110 | PHP_VAR_SERIALIZE_INIT(serialize_data);
111 |
112 | key = php_ds_pair_get_key(pair);
113 | val = php_ds_pair_get_value(pair);
114 |
115 | php_var_serialize(&buf, key, &serialize_data);
116 | php_var_serialize(&buf, val, &serialize_data);
117 |
118 | smart_str_0(&buf);
119 | SERIALIZE_SET_ZSTR(buf.s);
120 | zend_string_release(buf.s);
121 |
122 | PHP_VAR_SERIALIZE_DESTROY(serialize_data);
123 | return SUCCESS;
124 | }
125 |
126 | int php_ds_pair_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t length, zend_unserialize_data *data)
127 | {
128 | zval *key, *value;
129 | php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data;
130 |
131 | const unsigned char *pos = buffer;
132 | const unsigned char *max = buffer + length;
133 |
134 | PHP_VAR_UNSERIALIZE_INIT(unserialize_data);
135 |
136 | key = var_tmp_var(&unserialize_data);
137 | if ( ! php_var_unserialize(key, &pos, max, &unserialize_data)) {
138 | goto error;
139 | }
140 |
141 | value = var_tmp_var(&unserialize_data);
142 | if ( ! php_var_unserialize(value, &pos, max, &unserialize_data)) {
143 | goto error;
144 | }
145 |
146 | ZVAL_DS_PAIR(object, php_ds_pair_ex(key, value));
147 | PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
148 | return SUCCESS;
149 |
150 | error:
151 | PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
152 | UNSERIALIZE_ERROR();
153 | return FAILURE;
154 | }
155 |
--------------------------------------------------------------------------------
/src/php/handlers/php_map_handlers.c:
--------------------------------------------------------------------------------
1 | #include "php_map_handlers.h"
2 | #include "php_common_handlers.h"
3 | #include "../../ds/ds_map.h"
4 | #include "../objects/php_map.h"
5 |
6 | zend_object_handlers php_map_handlers;
7 |
8 | static zval *php_ds_map_read_dimension
9 | #if PHP_VERSION_ID >= 80000
10 | (zend_object *obj, zval *offset, int type, zval *rv) {
11 | ds_map_t *map = php_ds_map_fetch_object(obj)->map;
12 | #else
13 | (zval *obj, zval *offset, int type, zval *rv) {
14 | ds_map_t *map = Z_DS_MAP_P(obj);
15 | #endif
16 | if (offset == NULL) {
17 | ARRAY_ACCESS_PUSH_NOT_SUPPORTED();
18 | return NULL;
19 |
20 | } else {
21 | zval *value;
22 |
23 | // Dereference the offset if it's a reference.
24 | ZVAL_DEREF(offset);
25 |
26 | // `??`
27 | if (type == BP_VAR_IS) {
28 | if ( ! ds_htable_isset(map->table, offset, 0)) {
29 | return &EG(uninitialized_zval);;
30 | }
31 | }
32 |
33 | // Get the value from the map.
34 | value = ds_map_get(map, offset, NULL);
35 |
36 | // If we're accessing by reference we have to create a reference.
37 | // This is for access like $map[$a][$b] = $c
38 | if (value && type != BP_VAR_R && type != BP_VAR_IS) {
39 | ZVAL_MAKE_REF(value);
40 | }
41 |
42 | return value;
43 | }
44 | }
45 |
46 | static void php_ds_map_write_dimension
47 | #if PHP_VERSION_ID >= 80000
48 | (zend_object *obj, zval *offset, zval *value) {
49 | ds_map_t *map = php_ds_map_fetch_object(obj)->map;
50 | #else
51 | (zval *obj, zval *offset, zval *value) {
52 | ds_map_t *map = Z_DS_MAP_P(obj);
53 | #endif
54 | if (offset == NULL) {
55 | ARRAY_ACCESS_PUSH_NOT_SUPPORTED();
56 | return;
57 | }
58 | ZVAL_DEREF(offset);
59 | ds_htable_put(map->table, offset, value);
60 | }
61 |
62 | static int php_ds_map_has_dimension
63 | #if PHP_VERSION_ID >= 80000
64 | (zend_object *obj, zval *offset, int check_empty) {
65 | ds_map_t *map = php_ds_map_fetch_object(obj)->map;
66 | #else
67 | (zval *obj, zval *offset, int check_empty) {
68 | ds_map_t *map = Z_DS_MAP_P(obj);
69 | #endif
70 | ZVAL_DEREF(offset);
71 | return ds_htable_isset(map->table, offset, check_empty);
72 | }
73 |
74 | static void php_ds_map_unset_dimension
75 | #if PHP_VERSION_ID >= 80000
76 | (zend_object *obj, zval *offset) {
77 | ds_map_t *map = php_ds_map_fetch_object(obj)->map;
78 | #else
79 | (zval *obj, zval *offset) {
80 | ds_map_t *map = Z_DS_MAP_P(obj);
81 | #endif
82 | ZVAL_DEREF(offset);
83 | ds_htable_remove(map->table, offset, NULL);
84 | }
85 |
86 | static int php_ds_map_count_elements
87 | #if PHP_VERSION_ID >= 80000
88 | (zend_object *obj, zend_long *count) {
89 | ds_map_t *map = php_ds_map_fetch_object(obj)->map;
90 | #else
91 | (zval *obj, zend_long *count) {
92 | ds_map_t *map = Z_DS_MAP_P(obj);
93 | #endif
94 | *count = DS_MAP_SIZE(map);
95 | return SUCCESS;
96 | }
97 |
98 | static void php_ds_map_free_object(zend_object *object)
99 | {
100 | php_ds_map_t *intern = php_ds_map_fetch_object(object);
101 | ds_map_free(intern->map);
102 | zend_object_std_dtor(&intern->std);
103 | }
104 |
105 | static HashTable *php_ds_map_get_debug_info
106 | #if PHP_VERSION_ID >= 80000
107 | (zend_object *obj, int *is_temp) {
108 | ds_map_t *map = php_ds_map_fetch_object(obj)->map;
109 | #else
110 | (zval *obj, int *is_temp) {
111 | ds_map_t *map = Z_DS_MAP_P(obj);
112 | #endif
113 | *is_temp = 1;
114 | return ds_map_pairs_to_php_hashtable(map);
115 | }
116 |
117 | static zend_object *php_ds_map_clone_obj
118 | #if PHP_VERSION_ID >= 80000
119 | (zend_object *obj) {
120 | ds_map_t *map = php_ds_map_fetch_object(obj)->map;
121 | #else
122 | (zval *obj) {
123 | ds_map_t *map = Z_DS_MAP_P(obj);
124 | #endif
125 | return php_ds_map_create_clone(map);
126 | }
127 |
128 | static HashTable *php_ds_map_get_gc
129 | #if PHP_VERSION_ID >= 80000
130 | (zend_object *obj, zval **gc_data, int *gc_size) {
131 | ds_map_t *map = php_ds_map_fetch_object(obj)->map;
132 | #else
133 | (zval *obj, zval **gc_data, int *gc_size) {
134 | ds_map_t *map = Z_DS_MAP_P(obj);
135 | #endif
136 | if (DS_MAP_IS_EMPTY(map)) {
137 | *gc_data = NULL;
138 | *gc_size = 0;
139 | } else {
140 | *gc_data = (zval*) map->table->buckets;
141 | *gc_size = (int) map->table->next * 2;
142 | }
143 | return NULL;
144 | }
145 |
146 | void php_ds_register_map_handlers()
147 | {
148 | memcpy(&php_map_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
149 |
150 | php_map_handlers.offset = XtOffsetOf(php_ds_map_t, std);
151 | php_map_handlers.dtor_obj = zend_objects_destroy_object;
152 | php_map_handlers.get_gc = php_ds_map_get_gc;
153 | php_map_handlers.free_obj = php_ds_map_free_object;
154 | php_map_handlers.clone_obj = php_ds_map_clone_obj;
155 | php_map_handlers.get_debug_info = php_ds_map_get_debug_info;
156 | php_map_handlers.count_elements = php_ds_map_count_elements;
157 | php_map_handlers.read_dimension = php_ds_map_read_dimension;
158 | php_map_handlers.write_dimension = php_ds_map_write_dimension;
159 | php_map_handlers.has_dimension = php_ds_map_has_dimension;
160 | php_map_handlers.unset_dimension = php_ds_map_unset_dimension;
161 | php_map_handlers.cast_object = php_ds_default_cast_object;
162 | }
163 |
--------------------------------------------------------------------------------
/src/php/handlers/php_deque_handlers.c:
--------------------------------------------------------------------------------
1 | #include "php_common_handlers.h"
2 | #include "php_deque_handlers.h"
3 |
4 | #include "../objects/php_deque.h"
5 | #include "../../ds/ds_deque.h"
6 |
7 | zend_object_handlers php_deque_handlers;
8 |
9 | static zval *php_ds_deque_read_dimension
10 | #if PHP_VERSION_ID >= 80000
11 | (zend_object *obj, zval *offset, int type, zval *return_value) {
12 | ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque;
13 | #else
14 | (zval *obj, zval *offset, int type, zval *return_value) {
15 | ds_deque_t *deque = Z_DS_DEQUE_P(obj);
16 | #endif
17 | zval *value;
18 |
19 | // Dereference the offset if it's a reference.
20 | ZVAL_DEREF(offset);
21 |
22 | // `??`
23 | if (type == BP_VAR_IS) {
24 | if (Z_TYPE_P(offset) != IS_LONG || ! ds_deque_isset(deque, Z_LVAL_P(offset), 0)) {
25 | return &EG(uninitialized_zval);
26 | }
27 | }
28 |
29 | // Enforce strict integer index.
30 | if (Z_TYPE_P(offset) != IS_LONG) {
31 | INTEGER_INDEX_REQUIRED(offset);
32 | return NULL;
33 | }
34 |
35 | // Access the value at the given index.
36 | value = ds_deque_get(deque, Z_LVAL_P(offset));
37 |
38 | // If we're accessing by reference we have to create a reference.
39 | // This is for access like $deque[$a][$b] = $c
40 | if (value && type != BP_VAR_R && type != BP_VAR_IS) {
41 | ZVAL_MAKE_REF(value);
42 | }
43 |
44 | return value;
45 | }
46 |
47 | static void php_ds_deque_write_dimension
48 | #if PHP_VERSION_ID >= 80000
49 | (zend_object *obj, zval *offset, zval *value) {
50 | ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque;
51 | #else
52 | (zval *obj, zval *offset, zval *value) {
53 | ds_deque_t *deque = Z_DS_DEQUE_P(obj);
54 | #endif
55 | if (offset == NULL) { /* $v[] = ... */
56 | ds_deque_push(deque, value);
57 |
58 | } else {
59 | ZVAL_DEREF(offset);
60 |
61 | if (Z_TYPE_P(offset) != IS_LONG) {
62 | INTEGER_INDEX_REQUIRED(offset);
63 | } else {
64 | ds_deque_set(deque, Z_LVAL_P(offset), value);
65 | }
66 | }
67 | }
68 |
69 | static int php_ds_deque_has_dimension
70 | #if PHP_VERSION_ID >= 80000
71 | (zend_object *obj, zval *offset, int check_empty) {
72 | ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque;
73 | #else
74 | (zval *obj, zval *offset, int check_empty) {
75 | ds_deque_t *deque = Z_DS_DEQUE_P(obj);
76 | #endif
77 | if (Z_TYPE_P(offset) != IS_LONG) {
78 | return 0;
79 | }
80 |
81 | ZVAL_DEREF(offset);
82 |
83 | return ds_deque_isset(deque, Z_LVAL_P(offset), check_empty);
84 | }
85 |
86 | static void php_ds_deque_unset_dimension
87 | #if PHP_VERSION_ID >= 80000
88 | (zend_object *obj, zval *offset) {
89 | ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque;
90 | #else
91 | (zval *obj, zval *offset) {
92 | ds_deque_t *deque = Z_DS_DEQUE_P(obj);
93 | #endif
94 | zend_long index = 0;
95 | ZVAL_DEREF(offset);
96 |
97 | if (Z_TYPE_P(offset) == IS_LONG) {
98 | index = Z_LVAL_P(offset);
99 |
100 | } else {
101 | if (zend_parse_parameter(ZEND_PARSE_PARAMS_QUIET, 1, offset, "l", &index) == FAILURE) {
102 | return;
103 | }
104 | }
105 |
106 | if (ds_deque_index_exists(deque, index)) {
107 | ds_deque_remove(deque, index, NULL);
108 | }
109 | }
110 |
111 | static int php_ds_deque_count_elements
112 | #if PHP_VERSION_ID >= 80000
113 | (zend_object *obj, zend_long *count) {
114 | *count = php_ds_deque_fetch_object(obj)->deque->size;
115 | #else
116 | (zval *obj, zend_long *count) {
117 | *count = Z_DS_DEQUE_P(obj)->size;
118 | #endif
119 | return SUCCESS;
120 | }
121 |
122 | static void php_ds_deque_free_object(zend_object *object)
123 | {
124 | php_ds_deque_t *obj = php_ds_deque_fetch_object(object);
125 | ds_deque_free(obj->deque);
126 | zend_object_std_dtor(&obj->std);
127 | }
128 |
129 | static HashTable *php_ds_deque_get_debug_info
130 | #if PHP_VERSION_ID >= 80000
131 | (zend_object *obj, int *is_temp) {
132 | ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque;
133 | #else
134 | (zval *obj, int *is_temp) {
135 | ds_deque_t *deque = Z_DS_DEQUE_P(obj);
136 | #endif
137 | zval arr;
138 | *is_temp = 1;
139 | ds_deque_to_array(deque, &arr);
140 | return Z_ARRVAL(arr);
141 | }
142 |
143 | static zend_object *php_ds_deque_clone_obj
144 | #if PHP_VERSION_ID >= 80000
145 | (zend_object *obj) {
146 | return php_ds_deque_create_clone(php_ds_deque_fetch_object(obj)->deque);
147 | #else
148 | (zval *obj) {
149 | return php_ds_deque_create_clone(Z_DS_DEQUE_P(obj));
150 | #endif
151 | }
152 |
153 | static HashTable *php_ds_deque_get_gc
154 | #if PHP_VERSION_ID >= 80000
155 | (zend_object *obj, zval **gc_data, int *gc_count) {
156 | ds_deque_t *deque = php_ds_deque_fetch_object(obj)->deque;
157 | #else
158 | (zval *obj, zval **gc_data, int *gc_count) {
159 | ds_deque_t *deque = Z_DS_DEQUE_P(obj);
160 | #endif
161 | *gc_data = deque->buffer;
162 | *gc_count = (int) (deque->head == 0 ? deque->size : deque->capacity);
163 |
164 | return NULL;
165 | }
166 |
167 | void php_ds_register_deque_handlers()
168 | {
169 | memcpy(&php_deque_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
170 |
171 | php_deque_handlers.offset = XtOffsetOf(php_ds_deque_t, std);
172 |
173 | php_deque_handlers.dtor_obj = zend_objects_destroy_object;
174 | php_deque_handlers.free_obj = php_ds_deque_free_object;
175 | php_deque_handlers.get_gc = php_ds_deque_get_gc;
176 | php_deque_handlers.cast_object = php_ds_default_cast_object;
177 | php_deque_handlers.clone_obj = php_ds_deque_clone_obj;
178 | php_deque_handlers.get_debug_info = php_ds_deque_get_debug_info;
179 | php_deque_handlers.count_elements = php_ds_deque_count_elements;
180 | php_deque_handlers.read_dimension = php_ds_deque_read_dimension;
181 | php_deque_handlers.write_dimension = php_ds_deque_write_dimension;
182 | php_deque_handlers.has_dimension = php_ds_deque_has_dimension;
183 | php_deque_handlers.unset_dimension = php_ds_deque_unset_dimension;
184 | }
185 |
--------------------------------------------------------------------------------
/src/php/handlers/php_vector_handlers.c:
--------------------------------------------------------------------------------
1 | #include "php_common_handlers.h"
2 | #include "php_vector_handlers.h"
3 |
4 | #include "../objects/php_vector.h"
5 | #include "../../ds/ds_vector.h"
6 |
7 | zend_object_handlers php_vector_handlers;
8 |
9 | static zval *php_ds_vector_read_dimension
10 | #if PHP_VERSION_ID >= 80000
11 | (zend_object *obj, zval *offset, int type, zval *return_value) {
12 | ds_vector_t *vector = php_ds_vector_fetch_object(obj)->vector;
13 | #else
14 | (zval *obj, zval *offset, int type, zval *return_value) {
15 | ds_vector_t *vector = Z_DS_VECTOR_P(obj);
16 | #endif
17 | zval *value;
18 |
19 | // Dereference the offset if it's a reference.
20 | ZVAL_DEREF(offset);
21 |
22 | // `??`
23 | if (type == BP_VAR_IS) {
24 | if (Z_TYPE_P(offset) != IS_LONG || ! ds_vector_isset(vector, Z_LVAL_P(offset), 0)) {
25 | return &EG(uninitialized_zval);
26 | }
27 | }
28 |
29 | // Enforce strict integer index.
30 | if (Z_TYPE_P(offset) != IS_LONG) {
31 | INTEGER_INDEX_REQUIRED(offset);
32 | return NULL;
33 | }
34 |
35 | // Access the value at the given index.
36 | value = ds_vector_get(vector, Z_LVAL_P(offset));
37 |
38 | // If we're accessing by reference we have to create a reference.
39 | // This is for access like $deque[$a][$b] = $c
40 | if (value && type != BP_VAR_R && type != BP_VAR_IS) {
41 | ZVAL_MAKE_REF(value);
42 | }
43 |
44 | return value;
45 | }
46 |
47 | static void php_ds_vector_write_dimension
48 | #if PHP_VERSION_ID >= 80000
49 | (zend_object *obj, zval *offset, zval *value) {
50 | ds_vector_t *vector = php_ds_vector_fetch_object(obj)->vector;
51 | #else
52 | (zval *obj, zval *offset, zval *value) {
53 | ds_vector_t *vector = Z_DS_VECTOR_P(obj);
54 | #endif
55 | if (offset == NULL) { /* $v[] = ... */
56 | ds_vector_push(vector, value);
57 |
58 | } else {
59 | ZVAL_DEREF(offset);
60 |
61 | if (Z_TYPE_P(offset) != IS_LONG) {
62 | INTEGER_INDEX_REQUIRED(offset);
63 | } else {
64 | ds_vector_set(vector, Z_LVAL_P(offset), value);
65 | }
66 | }
67 | }
68 |
69 | static int php_ds_vector_has_dimension
70 | #if PHP_VERSION_ID >= 80000
71 | (zend_object *obj, zval *offset, int check_empty) {
72 | ds_vector_t *vector = php_ds_vector_fetch_object(obj)->vector;
73 | #else
74 | (zval *obj, zval *offset, int check_empty) {
75 | ds_vector_t *vector = Z_DS_VECTOR_P(obj);
76 | #endif
77 | if (Z_TYPE_P(offset) != IS_LONG) {
78 | return 0;
79 | }
80 | ZVAL_DEREF(offset);
81 |
82 | return ds_vector_isset(vector, Z_LVAL_P(offset), check_empty);
83 | }
84 |
85 | static void php_ds_vector_unset_dimension
86 | #if PHP_VERSION_ID >= 80000
87 | (zend_object *obj, zval *offset) {
88 | ds_vector_t *vector = php_ds_vector_fetch_object(obj)->vector;
89 | #else
90 | (zval *obj, zval *offset) {
91 | ds_vector_t *vector = Z_DS_VECTOR_P(obj);
92 | #endif
93 | zend_long index = 0;
94 | ZVAL_DEREF(offset);
95 |
96 | if (Z_TYPE_P(offset) == IS_LONG) {
97 | index = Z_LVAL_P(offset);
98 |
99 | } else {
100 | if (zend_parse_parameter(ZEND_PARSE_PARAMS_QUIET, 1, offset, "l", &index) == FAILURE) {
101 | return;
102 | }
103 | }
104 |
105 | if (ds_vector_index_exists(vector, index)) { // to avoid OutOfBounds
106 | ds_vector_remove(vector, index, NULL);
107 | }
108 | }
109 |
110 | static int php_ds_vector_count_elements
111 | #if PHP_VERSION_ID >= 80000
112 | (zend_object *obj, zend_long *count) {
113 | *count = php_ds_vector_fetch_object(obj)->vector->size; return SUCCESS;
114 | #else
115 | (zval *obj, zend_long *count) {
116 | *count = Z_DS_VECTOR_P(obj)->size; return SUCCESS;
117 | #endif
118 | }
119 |
120 | static void php_ds_vector_free_object(zend_object *obj)
121 | {
122 | php_ds_vector_t *vector = php_ds_vector_fetch_object(obj);
123 | ds_vector_free(vector->vector);
124 | zend_object_std_dtor(&vector->std);
125 | }
126 |
127 | static HashTable *php_ds_vector_get_debug_info
128 | #if PHP_VERSION_ID >= 80000
129 | (zend_object *obj, int *is_temp) {
130 | ds_vector_t *vector = php_ds_vector_fetch_object(obj)->vector;
131 | #else
132 | (zval *obj, int *is_temp) {
133 | ds_vector_t *vector = Z_DS_VECTOR_P(obj);
134 | #endif
135 | zval arr;
136 | *is_temp = 1;
137 | ds_vector_to_array(vector, &arr);
138 | return Z_ARRVAL(arr);
139 | }
140 |
141 | static zend_object *php_ds_vector_clone_obj
142 | #if PHP_VERSION_ID >= 80000
143 | (zend_object *obj) {
144 | return php_ds_vector_create_clone(php_ds_vector_fetch_object(obj)->vector);
145 | #else
146 | (zval *obj) {
147 | return php_ds_vector_create_clone(Z_DS_VECTOR_P(obj));
148 | #endif
149 | }
150 |
151 | static HashTable *php_ds_vector_get_gc
152 | #if PHP_VERSION_ID >= 80000
153 | (zend_object *obj, zval **gc_data, int *gc_count) {
154 | ds_vector_t *vector = php_ds_vector_fetch_object(obj)->vector;
155 | #else
156 | (zval *obj, zval **gc_data, int *gc_count) {
157 | ds_vector_t *vector = Z_DS_VECTOR_P(obj);
158 | #endif
159 | *gc_data = vector->buffer;
160 | *gc_count = (int) vector->size;
161 |
162 | return NULL;
163 | }
164 |
165 | void php_register_vector_handlers()
166 | {
167 | memcpy(&php_vector_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
168 |
169 | php_vector_handlers.offset = XtOffsetOf(php_ds_vector_t, std);
170 |
171 | php_vector_handlers.dtor_obj = zend_objects_destroy_object;
172 | php_vector_handlers.free_obj = php_ds_vector_free_object;
173 | php_vector_handlers.get_gc = php_ds_vector_get_gc;
174 | php_vector_handlers.clone_obj = php_ds_vector_clone_obj;
175 | php_vector_handlers.cast_object = php_ds_default_cast_object;
176 | php_vector_handlers.get_debug_info = php_ds_vector_get_debug_info;
177 | php_vector_handlers.count_elements = php_ds_vector_count_elements;
178 | php_vector_handlers.read_dimension = php_ds_vector_read_dimension;
179 | php_vector_handlers.write_dimension = php_ds_vector_write_dimension;
180 | php_vector_handlers.has_dimension = php_ds_vector_has_dimension;
181 | php_vector_handlers.unset_dimension = php_ds_vector_unset_dimension;
182 | }
183 |
--------------------------------------------------------------------------------
/src/common.c:
--------------------------------------------------------------------------------
1 | #include "common.h"
2 |
3 | zval *ds_allocate_zval_buffer(zend_long length)
4 | {
5 | return ecalloc(length, sizeof(zval));
6 | }
7 |
8 | uint32_t ds_next_power_of_2(uint32_t n, uint32_t min)
9 | {
10 | if (n < min) return min;
11 |
12 | n--;
13 | n |= n >> 1;
14 | n |= n >> 2;
15 | n |= n >> 4;
16 | n |= n >> 8;
17 | n |= n >> 16;
18 | n++;
19 |
20 | return n;
21 | }
22 |
23 | zval *ds_reallocate_zval_buffer(
24 | zval *buffer,
25 | zend_long length,
26 | zend_long current,
27 | zend_long used
28 | ) {
29 | if (length == current) {
30 | return buffer;
31 | }
32 |
33 | // Destruct zvals if we're truncating the buffer.
34 | if (length < used) {
35 | zend_long i;
36 |
37 | for (i = length; i < used; i++) {
38 | DTOR_AND_UNDEF(&buffer[i]);
39 | }
40 | }
41 |
42 | buffer = erealloc(buffer, length * sizeof(zval));
43 |
44 | // Clear out any new memory that was allocated.
45 | if (length > current) {
46 | memset(buffer + current, 0, (length - current) * sizeof(zval));
47 | }
48 |
49 | return buffer;
50 | }
51 |
52 | static int ds_zval_user_compare_func(const void *a, const void *b)
53 | {
54 | zval params[2];
55 | zval retval;
56 |
57 | zval *x = (zval*) a;
58 | zval *y = (zval*) b;
59 |
60 | ZVAL_COPY_VALUE(¶ms[0], x);
61 | ZVAL_COPY_VALUE(¶ms[1], y);
62 |
63 | DSG(user_compare_fci).param_count = 2;
64 | DSG(user_compare_fci).params = params;
65 | DSG(user_compare_fci).retval = &retval;
66 |
67 | if (zend_call_function(
68 | &DSG(user_compare_fci),
69 | &DSG(user_compare_fci_cache)) == SUCCESS) {
70 |
71 | return (int) zval_get_long(&retval);
72 | }
73 |
74 | return 0;
75 | }
76 |
77 | static int ds_zval_compare_func(const void *a, const void *b)
78 | {
79 | zval retval;
80 |
81 | zval *x = (zval*) a;
82 | zval *y = (zval*) b;
83 |
84 | if (compare_function(&retval, x, y) == SUCCESS) {
85 | return (int) zval_get_long(&retval);
86 | }
87 |
88 | return 0;
89 | }
90 |
91 | void ds_sort_zval_buffer(zval *buffer, zend_long size)
92 | {
93 | qsort(buffer, size, sizeof(zval), ds_zval_compare_func);
94 | }
95 |
96 | void ds_user_sort_zval_buffer(zval *buffer, zend_long size)
97 | {
98 | qsort(buffer, size, sizeof(zval), ds_zval_user_compare_func);
99 | }
100 |
101 | int ds_zval_isset(zval *value, int check_empty)
102 | {
103 | if (value == NULL) {
104 | return 0;
105 | }
106 |
107 | if ( ! check_empty) {
108 | return Z_TYPE_P(value) != IS_NULL;
109 | }
110 |
111 | return zend_is_true(value);
112 | }
113 |
114 | void ds_normalize_slice_args(
115 | zend_long *offset,
116 | zend_long *length,
117 | zend_long size
118 | ) {
119 | zend_long idx = *offset;
120 | zend_long len = *length;
121 |
122 | // If the offset is beyond the end or the length is zero, it's an empty slice.
123 | if (size == 0 || idx >= size) {
124 | *offset = 0;
125 | *length = 0;
126 |
127 | } else {
128 |
129 | // If index is negative, start that far from the end.
130 | if (idx < 0) {
131 | idx = MAX(0, size + idx);
132 | }
133 |
134 | // If length is given and negative, stop that far from the end.
135 | if (len < 0) {
136 | len = MAX(0, (size + len) - idx);
137 | }
138 |
139 | // If the length extends beyond the end, only go up to the end.
140 | if ((idx + len) > size) {
141 | len = MAX(0, size - idx);
142 | }
143 |
144 | *offset = idx;
145 | *length = len;
146 | }
147 | }
148 |
149 | void smart_str_appendz(smart_str *buffer, zval *value)
150 | {
151 | switch (Z_TYPE_P(value)) {
152 | case IS_STRING:
153 | smart_str_append(buffer, Z_STR_P(value));
154 | return;
155 | case IS_LONG:
156 | smart_str_append_long(buffer, Z_LVAL_P(value));
157 | return;
158 | }
159 |
160 | zend_string *str = zval_get_string(value);
161 | smart_str_append(buffer, str);
162 | zend_string_free(str);
163 | }
164 |
165 | zend_string *ds_join_zval_buffer(
166 | zval *buffer,
167 | zend_long size,
168 | char *glue,
169 | size_t len
170 | ) {
171 | smart_str str = {0};
172 |
173 | if (size <= 0) {
174 | return ZSTR_EMPTY_ALLOC();
175 | }
176 |
177 | if (size == 1) {
178 | return zval_get_string(buffer);
179 | }
180 |
181 | // Glue is optional, will use empty string by default if NULL
182 | if (glue && len) {
183 | zval *pos = buffer;
184 | zval *end = buffer + size - 1; // Exclude last value
185 |
186 | // Append each part and the glue right up to the last value.
187 | do {
188 | smart_str_appendz(&str, pos);
189 | smart_str_appendl(&str, glue, len);
190 | } while (++pos != end);
191 |
192 | // Append last value
193 | smart_str_appendz(&str, pos);
194 |
195 | } else {
196 | zval *pos = buffer;
197 | zval *end = buffer + size;
198 |
199 | // Append each part including the last, without glue.
200 | do {
201 | smart_str_appendz(&str, pos);
202 | } while (++pos != end);
203 | }
204 |
205 | smart_str_0(&str);
206 | return str.s;
207 | }
208 |
209 | bool ds_is_traversable(zval *value)
210 | {
211 | return Z_TYPE_P(value) == IS_OBJECT &&
212 | instanceof_function(Z_OBJCE_P(value), zend_ce_traversable);
213 | }
214 |
215 | bool ds_is_array(zval *value)
216 | {
217 | return Z_TYPE_P(value) == IS_ARRAY;
218 | }
219 |
220 | bool ds_php_array_uses_keys(HashTable *ht)
221 | {
222 | zend_string *key;
223 | zend_long index;
224 | zend_long expected = 0;
225 |
226 | ZEND_HASH_FOREACH_KEY(ht, index, key) {
227 | if (key || index != expected++) {
228 | return true;
229 | }
230 | }
231 |
232 | ZEND_HASH_FOREACH_END();
233 | return false;
234 | }
235 |
236 | void ds_reverse_zval_range(zval *x, zval *y)
237 | {
238 | for (; x < --y; ++x) SWAP_ZVAL(*x, *y);
239 | }
240 |
241 | void ds_throw_exception(zend_class_entry *ce, const char *format, ...)
242 | {
243 | va_list ap;
244 | zend_string *str;
245 |
246 | va_start(ap, format);
247 | str = vstrpprintf(0, format, ap);
248 | va_end(ap);
249 |
250 | zend_throw_exception(ce, str->val, 0);
251 | zend_string_free(str);
252 | }
253 |
--------------------------------------------------------------------------------
/src/php/iterators/php_htable_iterator.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 |
3 | #include "../../ds/ds_htable.h"
4 | #include "php_htable_iterator.h"
5 |
6 | static ds_htable_bucket_t *find_starting_bucket(ds_htable_t *table)
7 | {
8 | ds_htable_bucket_t *bucket = table->buckets;
9 |
10 | if (table->size != 0) {
11 | ds_htable_bucket_t *last = table->buckets + table->capacity;
12 |
13 | while (bucket != last && DS_HTABLE_BUCKET_DELETED(bucket)) {
14 | ++bucket;
15 | }
16 | }
17 |
18 | return bucket;
19 | }
20 |
21 | static void php_ds_htable_iterator_dtor(zend_object_iterator *iter)
22 | {
23 | ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter;
24 |
25 | OBJ_RELEASE(iterator->obj);
26 | DTOR_AND_UNDEF(&iterator->intern.data);
27 | }
28 |
29 | static int php_ds_htable_iterator_valid(zend_object_iterator *iter)
30 | {
31 | ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter;
32 | uint32_t size = iterator->table->size;
33 | uint32_t position = iterator->position;
34 |
35 | return position < size ? SUCCESS : FAILURE;
36 | }
37 |
38 | static zval *php_ds_htable_iterator_get_current_value(zend_object_iterator *iter)
39 | {
40 | ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter;
41 | ds_htable_bucket_t *bucket = iterator->bucket;
42 |
43 | if ( ! DS_HTABLE_BUCKET_DELETED(bucket)) {
44 | return &bucket->value;
45 | }
46 |
47 | return NULL;
48 | }
49 |
50 | static zval *php_ds_htable_iterator_get_current_keyval(zend_object_iterator *iter)
51 | {
52 | ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter;
53 | ds_htable_bucket_t *bucket = iterator->bucket;
54 |
55 | if ( ! DS_HTABLE_BUCKET_DELETED(bucket)) {
56 | return &bucket->key;
57 | }
58 |
59 | return NULL;
60 | }
61 |
62 | static void php_ds_htable_iterator_get_current_key(zend_object_iterator *iter, zval *key)
63 | {
64 | ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter;
65 | ds_htable_bucket_t *bucket = iterator->bucket;
66 |
67 | if ( ! DS_HTABLE_BUCKET_DELETED(bucket)) {
68 | ZVAL_COPY(key, &bucket->key);
69 | }
70 | }
71 |
72 | static zval *php_ds_htable_iterator_get_current_pair(zend_object_iterator *iter)
73 | {
74 | ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter;
75 | ds_htable_bucket_t *bucket = iterator->bucket;
76 |
77 | if ( ! DS_HTABLE_BUCKET_DELETED(bucket)) {
78 |
79 | zval *key = &bucket->key;
80 | zval *val = &bucket->value;
81 |
82 | zval *arr = &iterator->intern.data;
83 |
84 | Z_TRY_ADDREF_P(key);
85 | Z_TRY_ADDREF_P(val);
86 |
87 | array_init_size(arr, 2);
88 |
89 | add_next_index_zval(arr, key);
90 | add_next_index_zval(arr, val);
91 |
92 | return arr;
93 | }
94 |
95 | return NULL;
96 | }
97 |
98 | static void php_ds_htable_iterator_get_current_pos(zend_object_iterator *iter, zval *key)
99 | {
100 | ZVAL_LONG(key, ((ds_htable_iterator_t *) iter)->position);
101 | }
102 |
103 | static void php_ds_htable_iterator_move_forward(zend_object_iterator *iter)
104 | {
105 | ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter;
106 |
107 | if (++iterator->position < iterator->table->size) {
108 | do {
109 | ++iterator->bucket;
110 | } while (DS_HTABLE_BUCKET_DELETED(iterator->bucket));
111 | }
112 | }
113 |
114 | static void php_ds_htable_iterator_rewind(zend_object_iterator *iter)
115 | {
116 | ds_htable_iterator_t *iterator = (ds_htable_iterator_t *) iter;
117 |
118 | iterator->position = 0;
119 | iterator->bucket = find_starting_bucket(iterator->table);
120 | }
121 |
122 | static zend_object_iterator_funcs php_ds_htable_get_value_iterator_funcs = {
123 | php_ds_htable_iterator_dtor,
124 | php_ds_htable_iterator_valid,
125 | php_ds_htable_iterator_get_current_value, // value
126 | php_ds_htable_iterator_get_current_pos, // key
127 | php_ds_htable_iterator_move_forward,
128 | php_ds_htable_iterator_rewind
129 | };
130 |
131 | static zend_object_iterator_funcs php_ds_htable_get_key_iterator_funcs = {
132 | php_ds_htable_iterator_dtor,
133 | php_ds_htable_iterator_valid,
134 | php_ds_htable_iterator_get_current_keyval, // value
135 | php_ds_htable_iterator_get_current_pos, // key
136 | php_ds_htable_iterator_move_forward,
137 | php_ds_htable_iterator_rewind
138 | };
139 |
140 | static zend_object_iterator_funcs php_ds_htable_get_pair_iterator_funcs = {
141 | php_ds_htable_iterator_dtor,
142 | php_ds_htable_iterator_valid,
143 | php_ds_htable_iterator_get_current_pair, // value
144 | php_ds_htable_iterator_get_current_pos, // key
145 | php_ds_htable_iterator_move_forward,
146 | php_ds_htable_iterator_rewind
147 | };
148 |
149 | static zend_object_iterator_funcs php_ds_htable_get_assoc_iterator_funcs = {
150 | php_ds_htable_iterator_dtor,
151 | php_ds_htable_iterator_valid,
152 | php_ds_htable_iterator_get_current_value, // value
153 | php_ds_htable_iterator_get_current_key, // key
154 | php_ds_htable_iterator_move_forward,
155 | php_ds_htable_iterator_rewind
156 | };
157 |
158 |
159 | static zend_object_iterator *php_ds_htable_create_htable_iterator(
160 | zval *obj,
161 | ds_htable_t *table,
162 | zend_object_iterator_funcs *funcs,
163 | int by_ref
164 | ) {
165 | ds_htable_iterator_t *iterator;
166 |
167 | if (by_ref) {
168 | ITERATION_BY_REF_NOT_SUPPORTED();
169 | return NULL;
170 | }
171 |
172 | iterator = ecalloc(1, sizeof(ds_htable_iterator_t));
173 |
174 | zend_iterator_init((zend_object_iterator*) iterator);
175 |
176 | ZVAL_UNDEF(&iterator->intern.data);
177 |
178 | iterator->intern.funcs = funcs;
179 | iterator->table = table;
180 | iterator->obj = Z_OBJ_P(obj);
181 |
182 | // Add a reference to the object so that it doesn't get collected when
183 | // the iterated object is implict, eg. foreach ($obj->getInstance() as $value){ ... }
184 | #if PHP_VERSION_ID >= 70300
185 | GC_ADDREF(iterator->obj);
186 | #else
187 | ++GC_REFCOUNT(iterator->obj);
188 | #endif
189 |
190 | return (zend_object_iterator *) iterator;
191 | }
192 |
193 | zend_object_iterator *php_ds_htable_get_value_iterator_ex(
194 | zend_class_entry *ce,
195 | zval *obj,
196 | int by_ref,
197 | ds_htable_t *table
198 | ){
199 | return php_ds_htable_create_htable_iterator(
200 | obj, table, &php_ds_htable_get_value_iterator_funcs, by_ref);
201 | }
202 |
203 | zend_object_iterator *php_ds_htable_get_key_iterator_ex(
204 | zend_class_entry *ce,
205 | zval *obj,
206 | int by_ref,
207 | ds_htable_t *table
208 | ){
209 | return php_ds_htable_create_htable_iterator(
210 | obj, table, &php_ds_htable_get_key_iterator_funcs, by_ref);
211 | }
212 |
213 | zend_object_iterator *php_ds_htable_get_pair_iterator_ex(
214 | zend_class_entry *ce,
215 | zval *obj,
216 | int by_ref,
217 | ds_htable_t *table
218 | ){
219 | return php_ds_htable_create_htable_iterator(
220 | obj, table, &php_ds_htable_get_pair_iterator_funcs, by_ref);
221 | }
222 |
223 | zend_object_iterator *php_ds_htable_get_assoc_iterator_ex(
224 | zend_class_entry *ce,
225 | zval *obj,
226 | int by_ref,
227 | ds_htable_t *table
228 | ){
229 | return php_ds_htable_create_htable_iterator(
230 | obj, table, &php_ds_htable_get_assoc_iterator_funcs, by_ref);
231 | }
232 |
--------------------------------------------------------------------------------
/src/php/classes/php_set_ce.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 |
3 | #include "../parameters.h"
4 | #include "../arginfo.h"
5 |
6 | #include "../objects/php_set.h"
7 |
8 | #include "../iterators/php_set_iterator.h"
9 | #include "../handlers/php_set_handlers.h"
10 |
11 | #include "php_collection_ce.h"
12 | #include "php_set_ce.h"
13 |
14 | #define METHOD(name) PHP_METHOD(Set, name)
15 |
16 | zend_class_entry *php_ds_set_ce;
17 |
18 | METHOD(__construct)
19 | {
20 | PARSE_OPTIONAL_ZVAL(values);
21 |
22 | if (values) {
23 | ds_set_add_all(THIS_DS_SET(), values);
24 | }
25 | }
26 |
27 | METHOD(join)
28 | {
29 | if (ZEND_NUM_ARGS()) {
30 | PARSE_STRING();
31 | ds_set_join(THIS_DS_SET(), str, len, return_value);
32 | } else {
33 | ds_set_join(THIS_DS_SET(), NULL, 0, return_value);
34 | }
35 | }
36 |
37 | METHOD(allocate)
38 | {
39 | PARSE_LONG(capacity);
40 | ds_set_allocate(THIS_DS_SET(), capacity);
41 | }
42 |
43 | METHOD(capacity)
44 | {
45 | PARSE_NONE;
46 | RETURN_LONG(DS_SET_CAPACITY(THIS_DS_SET()));
47 | }
48 |
49 | METHOD(add)
50 | {
51 | PARSE_VARIADIC_ZVAL();
52 | ds_set_add_va(THIS_DS_SET(), argc, argv);
53 | }
54 |
55 | METHOD(remove)
56 | {
57 | PARSE_VARIADIC_ZVAL();
58 | ds_set_remove_va(THIS_DS_SET(), argc, argv);
59 | }
60 |
61 | METHOD(get)
62 | {
63 | PARSE_LONG(index);
64 | RETURN_ZVAL_COPY(ds_set_get(THIS_DS_SET(), index));
65 | }
66 |
67 | METHOD(contains)
68 | {
69 | PARSE_VARIADIC_ZVAL();
70 | RETURN_BOOL(ds_set_contains_va(THIS_DS_SET(), argc, argv));
71 | }
72 |
73 | METHOD(diff)
74 | {
75 | PARSE_OBJ(obj, php_ds_set_ce);
76 | RETURN_DS_SET(ds_set_diff(THIS_DS_SET(), Z_DS_SET_P(obj)));
77 | }
78 |
79 | METHOD(intersect)
80 | {
81 | PARSE_OBJ(obj, php_ds_set_ce);
82 | RETURN_DS_SET(ds_set_intersect(THIS_DS_SET(), Z_DS_SET_P(obj)));
83 | }
84 |
85 | METHOD(xor)
86 | {
87 | PARSE_OBJ(obj, php_ds_set_ce);
88 | RETURN_DS_SET(ds_set_xor(THIS_DS_SET(), Z_DS_SET_P(obj)));
89 | }
90 |
91 | METHOD(first)
92 | {
93 | PARSE_NONE;
94 | RETURN_ZVAL_COPY(ds_set_get_first(THIS_DS_SET()));
95 | }
96 |
97 | METHOD(last)
98 | {
99 | PARSE_NONE;
100 | RETURN_ZVAL_COPY(ds_set_get_last(THIS_DS_SET()));
101 | }
102 |
103 | METHOD(map)
104 | {
105 | PARSE_CALLABLE();
106 | RETURN_DS_SET(ds_set_map(THIS_DS_SET(), FCI_ARGS));
107 | }
108 |
109 | METHOD(merge)
110 | {
111 | PARSE_ZVAL(values);
112 | RETURN_DS_SET(ds_set_merge(THIS_DS_SET(), values));
113 | }
114 |
115 | METHOD(union)
116 | {
117 | PARSE_OBJ(obj, php_ds_set_ce);
118 | RETURN_DS_SET(ds_set_union(THIS_DS_SET(), Z_DS_SET_P(obj)));
119 | }
120 |
121 | METHOD(clear)
122 | {
123 | PARSE_NONE;
124 | ds_set_clear(THIS_DS_SET());
125 | }
126 |
127 | METHOD(toArray)
128 | {
129 | PARSE_NONE;
130 | ds_set_to_array(THIS_DS_SET(), return_value);
131 | }
132 |
133 | METHOD(count)
134 | {
135 | PARSE_NONE;
136 | RETURN_LONG(DS_SET_SIZE(THIS_DS_SET()));
137 | }
138 |
139 | METHOD(isEmpty)
140 | {
141 | PARSE_NONE;
142 | RETURN_BOOL(DS_SET_IS_EMPTY(THIS_DS_SET()));
143 | }
144 |
145 | METHOD(sort)
146 | {
147 | if (ZEND_NUM_ARGS()) {
148 | PARSE_COMPARE_CALLABLE();
149 | ds_set_sort_callback(THIS_DS_SET());
150 | } else {
151 | ds_set_sort(THIS_DS_SET());
152 | }
153 | }
154 |
155 | METHOD(sorted)
156 | {
157 | if (ZEND_NUM_ARGS()) {
158 | PARSE_COMPARE_CALLABLE();
159 | RETURN_DS_SET(ds_set_sorted_callback(THIS_DS_SET()));
160 | } else {
161 | RETURN_DS_SET(ds_set_sorted(THIS_DS_SET()));
162 | }
163 | }
164 |
165 | METHOD(copy)
166 | {
167 | PARSE_NONE;
168 | RETURN_OBJ(php_ds_set_create_clone(THIS_DS_SET()));
169 | }
170 |
171 | METHOD(reduce)
172 | {
173 | PARSE_CALLABLE_AND_OPTIONAL_ZVAL(initial);
174 | ds_set_reduce(THIS_DS_SET(), FCI_ARGS, initial, return_value);
175 | }
176 |
177 | METHOD(slice)
178 | {
179 | ds_set_t *set = THIS_DS_SET();
180 |
181 | PARSE_LONG_AND_OPTIONAL_ZVAL(index, length);
182 |
183 | if (ZEND_NUM_ARGS() > 1 && Z_TYPE_P(length) != IS_NULL) {
184 | if (Z_TYPE_P(length) != IS_LONG) {
185 | INTEGER_LENGTH_REQUIRED(length);
186 | } else {
187 | RETURN_DS_SET(ds_set_slice(set, index, Z_LVAL_P(length)));
188 | }
189 | } else {
190 | RETURN_DS_SET(ds_set_slice(set, index, DS_SET_SIZE(set)));
191 | }
192 | }
193 |
194 | METHOD(filter)
195 | {
196 | if (ZEND_NUM_ARGS()) {
197 | PARSE_CALLABLE();
198 | RETURN_DS_SET(ds_set_filter_callback(THIS_DS_SET(), FCI_ARGS));
199 | } else {
200 | RETURN_DS_SET(ds_set_filter(THIS_DS_SET()));
201 | }
202 | }
203 |
204 | METHOD(reverse)
205 | {
206 | PARSE_NONE;
207 | ds_set_reverse(THIS_DS_SET());
208 | }
209 |
210 | METHOD(reversed)
211 | {
212 | PARSE_NONE;
213 | RETURN_DS_SET(ds_set_reversed(THIS_DS_SET()));
214 | }
215 |
216 | METHOD(sum)
217 | {
218 | PARSE_NONE;
219 | ds_set_sum(THIS_DS_SET(), return_value);
220 | }
221 |
222 | METHOD(jsonSerialize)
223 | {
224 | PARSE_NONE;
225 | ds_set_to_array(THIS_DS_SET(), return_value);
226 | }
227 |
228 | METHOD(getIterator) {
229 | PARSE_NONE;
230 | ZVAL_COPY(return_value, getThis());
231 | }
232 |
233 |
234 | METHOD(offsetExists)
235 | {
236 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
237 | }
238 |
239 | METHOD(offsetGet)
240 | {
241 | PARSE_LONG(index);
242 | RETURN_ZVAL_COPY(ds_set_get(THIS_DS_SET(), index));
243 | }
244 |
245 | METHOD(offsetSet)
246 | {
247 | PARSE_ZVAL_ZVAL(offset, value);
248 |
249 | if (Z_TYPE_P(offset) == IS_NULL) {
250 | ds_set_add_va(THIS_DS_SET(), 1, value);
251 | } else {
252 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
253 | }
254 | }
255 |
256 | METHOD(offsetUnset)
257 | {
258 | ARRAY_ACCESS_BY_KEY_NOT_SUPPORTED();
259 | }
260 |
261 | void php_ds_register_set()
262 | {
263 | zend_class_entry ce;
264 |
265 | zend_function_entry methods[] = {
266 | PHP_DS_ME(Set, __construct)
267 | PHP_DS_ME(Set, add)
268 | PHP_DS_ME(Set, allocate)
269 | PHP_DS_ME(Set, capacity)
270 | PHP_DS_ME(Set, contains)
271 | PHP_DS_ME(Set, diff)
272 | PHP_DS_ME(Set, filter)
273 | PHP_DS_ME(Set, first)
274 | PHP_DS_ME(Set, get)
275 | PHP_DS_ME(Set, intersect)
276 | PHP_DS_ME(Set, join)
277 | PHP_DS_ME(Set, last)
278 | PHP_DS_ME(Set, map)
279 | PHP_DS_ME(Set, merge)
280 | PHP_DS_ME(Set, reduce)
281 | PHP_DS_ME(Set, remove)
282 | PHP_DS_ME(Set, reverse)
283 | PHP_DS_ME(Set, reversed)
284 | PHP_DS_ME(Set, slice)
285 | PHP_DS_ME(Set, sort)
286 | PHP_DS_ME(Set, sorted)
287 | PHP_DS_ME(Set, sum)
288 | PHP_DS_ME(Set, union)
289 | PHP_DS_ME(Set, xor)
290 | PHP_DS_ME(Set, getIterator)
291 |
292 | PHP_DS_ME(Set, offsetExists)
293 | PHP_DS_ME(Set, offsetGet)
294 | PHP_DS_ME(Set, offsetSet)
295 | PHP_DS_ME(Set, offsetUnset)
296 |
297 | PHP_DS_COLLECTION_ME_LIST(Set)
298 | PHP_FE_END
299 | };
300 |
301 | INIT_CLASS_ENTRY(ce, PHP_DS_NS(Set), methods);
302 |
303 | php_ds_set_ce = zend_register_internal_class(&ce);
304 | php_ds_set_ce->ce_flags |= ZEND_ACC_FINAL;
305 | php_ds_set_ce->create_object = php_ds_set_create_object;
306 | php_ds_set_ce->get_iterator = php_ds_set_get_iterator;
307 | php_ds_set_ce->serialize = php_ds_set_serialize;
308 | php_ds_set_ce->unserialize = php_ds_set_unserialize;
309 |
310 | zend_declare_class_constant_long(
311 | php_ds_set_ce,
312 | STR_AND_LEN("MIN_CAPACITY"),
313 | DS_HTABLE_MIN_CAPACITY
314 | );
315 |
316 | zend_class_implements(php_ds_set_ce, 2,
317 | collection_ce,
318 | zend_ce_arrayaccess
319 | );
320 |
321 | php_ds_register_set_handlers();
322 | }
323 |
--------------------------------------------------------------------------------
/src/php/classes/php_deque_ce.c:
--------------------------------------------------------------------------------
1 | #include "../../common.h"
2 |
3 | #include "../parameters.h"
4 | #include "../arginfo.h"
5 |
6 | #include "../objects/php_deque.h"
7 | #include "../iterators/php_deque_iterator.h"
8 | #include "../handlers/php_deque_handlers.h"
9 |
10 | #include "php_collection_ce.h"
11 | #include "php_sequence_ce.h"
12 | #include "php_deque_ce.h"
13 |
14 | #define METHOD(name) PHP_METHOD(Deque, name)
15 |
16 | zend_class_entry *php_ds_deque_ce;
17 |
18 | METHOD(__construct)
19 | {
20 | PARSE_OPTIONAL_ZVAL(values);
21 |
22 | if (values) {
23 | ds_deque_push_all(THIS_DS_DEQUE(), values);
24 | }
25 | }
26 |
27 | METHOD(join)
28 | {
29 | if (ZEND_NUM_ARGS()) {
30 | PARSE_STRING();
31 | ds_deque_join(THIS_DS_DEQUE(), str, len, return_value);
32 | } else {
33 | ds_deque_join(THIS_DS_DEQUE(), NULL, 0, return_value);
34 | }
35 | }
36 |
37 | METHOD(allocate)
38 | {
39 | PARSE_LONG(capacity);
40 | ds_deque_allocate(THIS_DS_DEQUE(), capacity);
41 | }
42 |
43 | METHOD(apply)
44 | {
45 | PARSE_CALLABLE();
46 | ds_deque_apply(THIS_DS_DEQUE(), FCI_ARGS);
47 | }
48 |
49 | METHOD(capacity)
50 | {
51 | PARSE_NONE;
52 | RETURN_LONG((THIS_DS_DEQUE())->capacity);
53 | }
54 |
55 | METHOD(map)
56 | {
57 | PARSE_CALLABLE();
58 | RETURN_DS_DEQUE(ds_deque_map(THIS_DS_DEQUE(), FCI_ARGS));
59 | }
60 |
61 | METHOD(merge)
62 | {
63 | PARSE_ZVAL(values);
64 | RETURN_DS_DEQUE(ds_deque_merge(THIS_DS_DEQUE(), values));
65 | }
66 |
67 | METHOD(reduce)
68 | {
69 | PARSE_CALLABLE_AND_OPTIONAL_ZVAL(initial);
70 | ds_deque_reduce(THIS_DS_DEQUE(), initial, return_value, FCI_ARGS);
71 | }
72 |
73 | METHOD(filter)
74 | {
75 | if (ZEND_NUM_ARGS()) {
76 | PARSE_CALLABLE();
77 | RETURN_DS_DEQUE(ds_deque_filter_callback(THIS_DS_DEQUE(), FCI_ARGS));
78 | } else {
79 | PARSE_NONE;
80 | RETURN_DS_DEQUE(ds_deque_filter(THIS_DS_DEQUE()));
81 | }
82 | }
83 |
84 | METHOD(slice)
85 | {
86 | ds_deque_t *deque = THIS_DS_DEQUE();
87 |
88 | PARSE_LONG_AND_OPTIONAL_ZVAL(index, length);
89 |
90 | if (ZEND_NUM_ARGS() > 1 && Z_TYPE_P(length) != IS_NULL) {
91 | if (Z_TYPE_P(length) != IS_LONG) {
92 | INTEGER_LENGTH_REQUIRED(length);
93 | } else {
94 | RETURN_DS_DEQUE(ds_deque_slice(deque, index, Z_LVAL_P(length)));
95 | }
96 | } else {
97 | RETURN_DS_DEQUE(ds_deque_slice(deque, index, deque->size));
98 | }
99 | }
100 |
101 | METHOD(sort)
102 | {
103 | ds_deque_t *sorted = THIS_DS_DEQUE();
104 |
105 | if (ZEND_NUM_ARGS()) {
106 | PARSE_COMPARE_CALLABLE();
107 | ds_deque_sort_callback(sorted);
108 | } else {
109 | ds_deque_sort(sorted);
110 | }
111 | }
112 |
113 | METHOD(sorted)
114 | {
115 | ds_deque_t *sorted = ds_deque_clone(THIS_DS_DEQUE());
116 |
117 | if (ZEND_NUM_ARGS()) {
118 | PARSE_COMPARE_CALLABLE();
119 | ds_deque_sort_callback(sorted);
120 | } else {
121 | ds_deque_sort(sorted);
122 | }
123 |
124 | RETURN_DS_DEQUE(sorted);
125 | }
126 |
127 | METHOD(push)
128 | {
129 | PARSE_VARIADIC_ZVAL();
130 | if (argc == 1) {
131 | ds_deque_push(THIS_DS_DEQUE(), argv);
132 | } else {
133 | ds_deque_push_va(THIS_DS_DEQUE(), argc, argv);
134 | }
135 | }
136 |
137 | METHOD(unshift)
138 | {
139 | PARSE_VARIADIC_ZVAL();
140 | ds_deque_unshift_va(THIS_DS_DEQUE(), argc, argv);
141 | }
142 |
143 | METHOD(pop)
144 | {
145 | PARSE_NONE;
146 | ds_deque_pop_throw(THIS_DS_DEQUE(), return_value);
147 | }
148 |
149 | METHOD(shift)
150 | {
151 | PARSE_NONE;
152 | ds_deque_shift_throw(THIS_DS_DEQUE(), return_value);
153 | }
154 |
155 | METHOD(first)
156 | {
157 | PARSE_NONE;
158 | RETURN_ZVAL_COPY(ds_deque_get_first_throw(THIS_DS_DEQUE()));
159 | }
160 |
161 | METHOD(last)
162 | {
163 | PARSE_NONE;
164 | RETURN_ZVAL_COPY(ds_deque_get_last_throw(THIS_DS_DEQUE()));
165 | }
166 |
167 | METHOD(count)
168 | {
169 | ds_deque_t *deque = THIS_DS_DEQUE();
170 | PARSE_NONE;
171 | RETURN_LONG(deque->size);
172 | }
173 |
174 | METHOD(clear)
175 | {
176 | PARSE_NONE;
177 | ds_deque_clear(THIS_DS_DEQUE());
178 | }
179 |
180 | METHOD(contains)
181 | {
182 | PARSE_VARIADIC_ZVAL();
183 | RETURN_BOOL(ds_deque_contains_va(THIS_DS_DEQUE(), argc, argv));
184 | }
185 |
186 | METHOD(sum)
187 | {
188 | PARSE_NONE;
189 | ds_deque_sum(THIS_DS_DEQUE(), return_value);
190 | }
191 |
192 | METHOD(toArray)
193 | {
194 | PARSE_NONE;
195 | ds_deque_to_array(THIS_DS_DEQUE(), return_value);
196 | }
197 |
198 | METHOD(get)
199 | {
200 | PARSE_LONG(index);
201 | RETURN_ZVAL_COPY(ds_deque_get(THIS_DS_DEQUE(), index));
202 | }
203 |
204 | METHOD(set)
205 | {
206 | PARSE_LONG_AND_ZVAL(index, value);
207 | ds_deque_set(THIS_DS_DEQUE(), index, value);
208 | }
209 |
210 | METHOD(find)
211 | {
212 | PARSE_ZVAL(value);
213 | ds_deque_find(THIS_DS_DEQUE(), value, return_value);
214 | }
215 |
216 | METHOD(remove)
217 | {
218 | PARSE_LONG(index);
219 | ds_deque_remove(THIS_DS_DEQUE(), index, return_value);
220 | }
221 |
222 | METHOD(insert)
223 | {
224 | PARSE_LONG_AND_VARIADIC_ZVAL(index);
225 | ds_deque_insert_va(THIS_DS_DEQUE(), index, argc, argv);
226 | }
227 |
228 | METHOD(reverse)
229 | {
230 | PARSE_NONE;
231 | ds_deque_reverse(THIS_DS_DEQUE());
232 | }
233 |
234 | METHOD(reversed)
235 | {
236 | PARSE_NONE;
237 | RETURN_DS_DEQUE(ds_deque_reversed(THIS_DS_DEQUE()));
238 | }
239 |
240 | METHOD(rotate)
241 | {
242 | PARSE_LONG(rotations);
243 | ds_deque_rotate(THIS_DS_DEQUE(), rotations);
244 | }
245 |
246 | METHOD(isEmpty)
247 | {
248 | PARSE_NONE;
249 | RETURN_BOOL(DS_DEQUE_IS_EMPTY(THIS_DS_DEQUE()));
250 | }
251 |
252 | METHOD(copy)
253 | {
254 | PARSE_NONE;
255 | RETURN_OBJ(php_ds_deque_create_clone(THIS_DS_DEQUE()));
256 | }
257 |
258 | METHOD(jsonSerialize)
259 | {
260 | PARSE_NONE;
261 | ds_deque_to_array(THIS_DS_DEQUE(), return_value);
262 | }
263 |
264 | METHOD(getIterator) {
265 | PARSE_NONE;
266 | ZVAL_COPY(return_value, getThis());
267 | }
268 |
269 | METHOD(offsetExists)
270 | {
271 | PARSE_LONG(index);
272 | RETURN_BOOL(ds_deque_isset(THIS_DS_DEQUE(), index, false));
273 | }
274 |
275 | METHOD(offsetGet)
276 | {
277 | PARSE_LONG(index);
278 | RETURN_ZVAL_COPY(ds_deque_get(THIS_DS_DEQUE(), index));
279 | }
280 |
281 | METHOD(offsetSet)
282 | {
283 | PARSE_ZVAL_ZVAL(offset, value);
284 |
285 | if (Z_TYPE_P(offset) == IS_NULL) {
286 | ds_deque_push(THIS_DS_DEQUE(), value);
287 | } else {
288 | if (Z_TYPE_P(offset) != IS_LONG) {
289 | INTEGER_INDEX_REQUIRED(offset);
290 | } else {
291 | ds_deque_set(THIS_DS_DEQUE(), Z_LVAL_P(offset), value);
292 | }
293 | }
294 | }
295 |
296 | METHOD(offsetUnset)
297 | {
298 | PARSE_LONG(index);
299 | ds_deque_remove(THIS_DS_DEQUE(), index, return_value);
300 | }
301 |
302 | void php_ds_register_deque()
303 | {
304 | zend_class_entry ce;
305 |
306 | zend_function_entry methods[] = {
307 | PHP_DS_ME(Deque, __construct)
308 | PHP_DS_ME(Deque, getIterator)
309 |
310 | PHP_DS_COLLECTION_ME_LIST(Deque)
311 | PHP_DS_SEQUENCE_ME_LIST(Deque)
312 | PHP_FE_END
313 | };
314 |
315 | INIT_CLASS_ENTRY(ce, PHP_DS_NS(Deque), methods);
316 |
317 | php_ds_deque_ce = zend_register_internal_class(&ce);
318 | php_ds_deque_ce->ce_flags |= ZEND_ACC_FINAL;
319 | php_ds_deque_ce->create_object = php_ds_deque_create_object;
320 | php_ds_deque_ce->get_iterator = php_ds_deque_get_iterator;
321 | php_ds_deque_ce->serialize = php_ds_deque_serialize;
322 | php_ds_deque_ce->unserialize = php_ds_deque_unserialize;
323 |
324 | zend_declare_class_constant_long(php_ds_deque_ce, STR_AND_LEN("MIN_CAPACITY"), DS_DEQUE_MIN_CAPACITY);
325 | zend_class_implements(php_ds_deque_ce, 1, sequence_ce);
326 |
327 | php_ds_register_deque_handlers();
328 | }
329 |
--------------------------------------------------------------------------------