├── .editorconfig ├── .github └── workflows │ └── main.yml ├── .gitignore ├── .valgrindrc ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README.md ├── appveyor.yml ├── composer.json ├── config.m4 ├── config.w32 ├── dev.sh ├── docker-compose.yml ├── ext-ds.ini ├── package.xml ├── php_ds.c ├── php_ds.h ├── phpunit.xml ├── sandbox.php ├── src ├── common.c ├── common.h ├── ds │ ├── ds_deque.c │ ├── ds_deque.h │ ├── ds_htable.c │ ├── ds_htable.h │ ├── ds_map.c │ ├── ds_map.h │ ├── ds_priority_queue.c │ ├── ds_priority_queue.h │ ├── ds_queue.c │ ├── ds_queue.h │ ├── ds_set.c │ ├── ds_set.h │ ├── ds_stack.c │ ├── ds_stack.h │ ├── ds_vector.c │ └── ds_vector.h └── php │ ├── arginfo.h │ ├── classes │ ├── php_collection_ce.c │ ├── php_collection_ce.h │ ├── php_deque_ce.c │ ├── php_deque_ce.h │ ├── php_hashable_ce.c │ ├── php_hashable_ce.h │ ├── php_map_ce.c │ ├── php_map_ce.h │ ├── php_pair_ce.c │ ├── php_pair_ce.h │ ├── php_priority_queue_ce.c │ ├── php_priority_queue_ce.h │ ├── php_queue_ce.c │ ├── php_queue_ce.h │ ├── php_sequence_ce.c │ ├── php_sequence_ce.h │ ├── php_set_ce.c │ ├── php_set_ce.h │ ├── php_stack_ce.c │ ├── php_stack_ce.h │ ├── php_vector_ce.c │ └── php_vector_ce.h │ ├── handlers │ ├── php_common_handlers.c │ ├── php_common_handlers.h │ ├── php_deque_handlers.c │ ├── php_deque_handlers.h │ ├── php_map_handlers.c │ ├── php_map_handlers.h │ ├── php_pair_handlers.c │ ├── php_pair_handlers.h │ ├── php_priority_queue_handlers.c │ ├── php_priority_queue_handlers.h │ ├── php_queue_handlers.c │ ├── php_queue_handlers.h │ ├── php_set_handlers.c │ ├── php_set_handlers.h │ ├── php_stack_handlers.c │ ├── php_stack_handlers.h │ ├── php_vector_handlers.c │ └── php_vector_handlers.h │ ├── iterators │ ├── php_deque_iterator.c │ ├── php_deque_iterator.h │ ├── php_htable_iterator.c │ ├── php_htable_iterator.h │ ├── php_map_iterator.c │ ├── php_map_iterator.h │ ├── php_priority_queue_iterator.c │ ├── php_priority_queue_iterator.h │ ├── php_queue_iterator.c │ ├── php_queue_iterator.h │ ├── php_set_iterator.c │ ├── php_set_iterator.h │ ├── php_stack_iterator.c │ ├── php_stack_iterator.h │ ├── php_vector_iterator.c │ └── php_vector_iterator.h │ ├── objects │ ├── php_deque.c │ ├── php_deque.h │ ├── php_map.c │ ├── php_map.h │ ├── php_pair.c │ ├── php_pair.h │ ├── php_priority_queue.c │ ├── php_priority_queue.h │ ├── php_queue.c │ ├── php_queue.h │ ├── php_set.c │ ├── php_set.h │ ├── php_stack.c │ ├── php_stack.h │ ├── php_vector.c │ └── php_vector.h │ └── parameters.h └── test.php /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *. 2 | *.dep 3 | *.ac 4 | *.gcda 5 | *.gcno 6 | *.la 7 | *.lo 8 | *.loT 9 | *.mem 10 | *.mk 11 | *.o 12 | *.slo 13 | *.tgz 14 | *~ 15 | .#* 16 | .deps 17 | .idea 18 | .libs 19 | .phpunit.result.cache 20 | /include 21 | acinclude.m4 22 | aclocal.m4 23 | autom4te.cache 24 | build 25 | clean 26 | composer.lock 27 | config.cache 28 | config.guess 29 | config.h 30 | config.h.in 31 | config.log 32 | config.nice 33 | config.status 34 | config.sub 35 | configure 36 | configure.in 37 | install 38 | install-sh 39 | libs 40 | libtool 41 | ltmain.sh 42 | Makefile 43 | Makefile.fragments 44 | Makefile.global 45 | Makefile.objects 46 | missing 47 | mkinstalldirs 48 | modules 49 | run-tests.php 50 | test 51 | vendor 52 | ~.tgz -------------------------------------------------------------------------------- /.valgrindrc: -------------------------------------------------------------------------------- 1 | --memcheck:leak-check=full 2 | --memcheck:track-origins=yes 3 | --memcheck:error-exitcode=1 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Native Data Structures for PHP 2 | 3 | [![Build Status](https://github.com/php-ds/ext-ds/workflows/CI/badge.svg)](https://github.com/php-ds/ext-ds/actions?query=workflow%3A%22CI%22+branch%3Amaster) 4 | [![Build status](https://ci.appveyor.com/api/projects/status/9w0xitp3q04hdu1d?svg=true)](https://ci.appveyor.com/project/rtheunissen/ext-ds) 5 | [![PECL](https://img.shields.io/badge/PECL-1.6.0-blue.svg)](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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "php-ds/extension", 3 | "license": "MIT", 4 | "keywords": [], 5 | "authors": [ 6 | { 7 | "name": "Rudi Theunissen", 8 | "email": "rudolf.theunissen@gmail.com" 9 | } 10 | ], 11 | "minimum-stability": "dev", 12 | "require-dev": { 13 | "php-ds/tests": "^1.5" 14 | }, 15 | "scripts": { 16 | "test" : "php test.php", 17 | "memtest": "USE_ZEND_ALLOC=0 ZEND_DONT_UNLOAD_MODULES=1 valgrind php test.php" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /dev.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | docker-compose run --rm --build --interactive --tty dev /bin/sh -------------------------------------------------------------------------------- /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" -------------------------------------------------------------------------------- /ext-ds.ini: -------------------------------------------------------------------------------- 1 | extension=ds.so -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | vendor/php-ds/tests/tests 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /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'; -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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_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/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_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/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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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_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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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_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/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_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.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/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_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/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/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_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/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_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/classes/php_vector_ce.c: -------------------------------------------------------------------------------- 1 | #include "../../common.h" 2 | 3 | #include "../parameters.h" 4 | #include "../arginfo.h" 5 | 6 | #include "../objects/php_vector.h" 7 | #include "../iterators/php_vector_iterator.h" 8 | #include "../handlers/php_vector_handlers.h" 9 | 10 | #include "php_collection_ce.h" 11 | #include "php_sequence_ce.h" 12 | #include "php_vector_ce.h" 13 | 14 | #define METHOD(name) PHP_METHOD(Vector, name) 15 | 16 | zend_class_entry *php_ds_vector_ce; 17 | 18 | METHOD(__construct) 19 | { 20 | PARSE_OPTIONAL_ZVAL(values); 21 | 22 | if (values) { 23 | ds_vector_push_all(THIS_DS_VECTOR(), values); 24 | } 25 | } 26 | 27 | METHOD(allocate) 28 | { 29 | PARSE_LONG(capacity); 30 | ds_vector_allocate(THIS_DS_VECTOR(), capacity); 31 | } 32 | 33 | METHOD(apply) 34 | { 35 | PARSE_CALLABLE(); 36 | ds_vector_apply(THIS_DS_VECTOR(), FCI_ARGS); 37 | } 38 | 39 | METHOD(capacity) 40 | { 41 | PARSE_NONE; 42 | RETURN_LONG((THIS_DS_VECTOR())->capacity); 43 | } 44 | 45 | METHOD(clear) 46 | { 47 | PARSE_NONE; 48 | ds_vector_clear(THIS_DS_VECTOR()); 49 | } 50 | 51 | METHOD(contains) 52 | { 53 | PARSE_VARIADIC_ZVAL(); 54 | RETURN_BOOL(ds_vector_contains_va(THIS_DS_VECTOR(), argc, argv)); 55 | } 56 | 57 | METHOD(copy) 58 | { 59 | PARSE_NONE; 60 | RETURN_OBJ(php_ds_vector_create_clone(THIS_DS_VECTOR())); 61 | } 62 | 63 | METHOD(count) 64 | { 65 | PARSE_NONE; 66 | RETURN_LONG(DS_VECTOR_SIZE(THIS_DS_VECTOR())); 67 | } 68 | 69 | METHOD(filter) 70 | { 71 | if (ZEND_NUM_ARGS()) { 72 | PARSE_CALLABLE(); 73 | RETURN_DS_VECTOR(ds_vector_filter_callback(THIS_DS_VECTOR(), FCI_ARGS)); 74 | } else { 75 | RETURN_DS_VECTOR(ds_vector_filter(THIS_DS_VECTOR())); 76 | } 77 | } 78 | 79 | METHOD(find) 80 | { 81 | PARSE_ZVAL(value); 82 | ds_vector_find(THIS_DS_VECTOR(), value, return_value); 83 | } 84 | 85 | METHOD(first) 86 | { 87 | PARSE_NONE; 88 | RETURN_ZVAL_COPY(ds_vector_get_first_throw(THIS_DS_VECTOR())); 89 | } 90 | 91 | METHOD(get) 92 | { 93 | PARSE_LONG(index); 94 | RETURN_ZVAL_COPY(ds_vector_get(THIS_DS_VECTOR(), index)); 95 | } 96 | 97 | METHOD(insert) 98 | { 99 | PARSE_LONG_AND_VARIADIC_ZVAL(index); 100 | ds_vector_insert_va(THIS_DS_VECTOR(), index, argc, argv); 101 | } 102 | 103 | METHOD(isEmpty) 104 | { 105 | PARSE_NONE; 106 | RETURN_BOOL(DS_VECTOR_IS_EMPTY(THIS_DS_VECTOR())); 107 | } 108 | 109 | METHOD(join) 110 | { 111 | if (ZEND_NUM_ARGS()) { 112 | PARSE_STRING(); 113 | ds_vector_join(THIS_DS_VECTOR(), str, len, return_value); 114 | } else { 115 | ds_vector_join(THIS_DS_VECTOR(), NULL, 0, return_value); 116 | } 117 | } 118 | 119 | METHOD(jsonSerialize) 120 | { 121 | PARSE_NONE; 122 | ds_vector_to_array(THIS_DS_VECTOR(), return_value); 123 | } 124 | 125 | METHOD(last) 126 | { 127 | PARSE_NONE; 128 | RETURN_ZVAL_COPY(ds_vector_get_last_throw(THIS_DS_VECTOR())); 129 | } 130 | 131 | METHOD(map) 132 | { 133 | PARSE_CALLABLE(); 134 | RETURN_DS_VECTOR(ds_vector_map(THIS_DS_VECTOR(), FCI_ARGS)); 135 | } 136 | 137 | METHOD(merge) 138 | { 139 | PARSE_ZVAL(values); 140 | RETURN_DS_VECTOR(ds_vector_merge(THIS_DS_VECTOR(), values)); 141 | } 142 | 143 | METHOD(pop) 144 | { 145 | PARSE_NONE; 146 | ds_vector_pop_throw(THIS_DS_VECTOR(), return_value); 147 | } 148 | 149 | METHOD(push) 150 | { 151 | PARSE_VARIADIC_ZVAL(); 152 | ds_vector_push_va(THIS_DS_VECTOR(), argc, argv); 153 | } 154 | 155 | METHOD(push_one) 156 | { 157 | PARSE_ZVAL(value); 158 | ds_vector_push(THIS_DS_VECTOR(), value); 159 | } 160 | 161 | METHOD(reduce) 162 | { 163 | PARSE_CALLABLE_AND_OPTIONAL_ZVAL(initial); 164 | ds_vector_reduce(THIS_DS_VECTOR(), initial, return_value, FCI_ARGS); 165 | } 166 | 167 | METHOD(remove) 168 | { 169 | PARSE_LONG(index); 170 | ds_vector_remove(THIS_DS_VECTOR(), index, return_value); 171 | } 172 | 173 | METHOD(reverse) 174 | { 175 | PARSE_NONE; 176 | ds_vector_reverse(THIS_DS_VECTOR()); 177 | } 178 | 179 | METHOD(reversed) 180 | { 181 | PARSE_NONE; 182 | RETURN_DS_VECTOR(ds_vector_reversed(THIS_DS_VECTOR())); 183 | } 184 | 185 | METHOD(rotate) 186 | { 187 | PARSE_LONG(rotations); 188 | ds_vector_rotate(THIS_DS_VECTOR(), rotations); 189 | } 190 | 191 | METHOD(set) 192 | { 193 | PARSE_LONG_AND_ZVAL(index, value); 194 | ds_vector_set(THIS_DS_VECTOR(), index, value); 195 | } 196 | 197 | METHOD(shift) 198 | { 199 | PARSE_NONE; 200 | ds_vector_shift_throw(THIS_DS_VECTOR(), return_value); 201 | } 202 | 203 | METHOD(slice) 204 | { 205 | ds_vector_t *vector = THIS_DS_VECTOR(); 206 | 207 | PARSE_LONG_AND_OPTIONAL_ZVAL(index, length); 208 | 209 | if (ZEND_NUM_ARGS() > 1 && Z_TYPE_P(length) != IS_NULL) { 210 | if (Z_TYPE_P(length) != IS_LONG) { 211 | INTEGER_LENGTH_REQUIRED(length); 212 | } else { 213 | RETURN_DS_VECTOR(ds_vector_slice(vector, index, Z_LVAL_P(length))); 214 | } 215 | } else { 216 | RETURN_DS_VECTOR(ds_vector_slice(vector, index, vector->size)); 217 | } 218 | } 219 | 220 | METHOD(sort) 221 | { 222 | ds_vector_t *vector = THIS_DS_VECTOR(); 223 | 224 | if (ZEND_NUM_ARGS()) { 225 | PARSE_COMPARE_CALLABLE(); 226 | ds_vector_sort_callback(vector); 227 | } else { 228 | ds_vector_sort(vector); 229 | } 230 | } 231 | 232 | METHOD(sorted) 233 | { 234 | ds_vector_t *vector = ds_vector_clone(THIS_DS_VECTOR()); 235 | 236 | if (ZEND_NUM_ARGS()) { 237 | PARSE_COMPARE_CALLABLE(); 238 | ds_vector_sort_callback(vector); 239 | } else { 240 | ds_vector_sort(vector); 241 | } 242 | 243 | RETURN_DS_VECTOR(vector); 244 | } 245 | 246 | METHOD(sum) 247 | { 248 | PARSE_NONE; 249 | ds_vector_sum(THIS_DS_VECTOR(), return_value); 250 | } 251 | 252 | METHOD(toArray) 253 | { 254 | PARSE_NONE; 255 | ds_vector_to_array(THIS_DS_VECTOR(), return_value); 256 | } 257 | 258 | METHOD(unshift) 259 | { 260 | PARSE_VARIADIC_ZVAL(); 261 | ds_vector_unshift_va(THIS_DS_VECTOR(), argc, argv); 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_vector_isset(THIS_DS_VECTOR(), index, false)); 273 | } 274 | 275 | METHOD(offsetGet) 276 | { 277 | PARSE_LONG(index); 278 | RETURN_ZVAL_COPY(ds_vector_get(THIS_DS_VECTOR(), index)); 279 | } 280 | 281 | METHOD(offsetSet) 282 | { 283 | PARSE_ZVAL_ZVAL(offset, value); 284 | 285 | if (Z_TYPE_P(offset) == IS_NULL) { 286 | ds_vector_push(THIS_DS_VECTOR(), value); 287 | } else { 288 | if (Z_TYPE_P(offset) != IS_LONG) { 289 | INTEGER_INDEX_REQUIRED(offset); 290 | } else { 291 | ds_vector_set(THIS_DS_VECTOR(), Z_LVAL_P(offset), value); 292 | } 293 | } 294 | } 295 | 296 | METHOD(offsetUnset) 297 | { 298 | PARSE_LONG(index); 299 | ds_vector_remove(THIS_DS_VECTOR(), index, return_value); 300 | } 301 | 302 | void php_ds_register_vector() 303 | { 304 | zend_class_entry ce; 305 | 306 | zend_function_entry methods[] = { 307 | PHP_DS_ME(Vector, __construct) 308 | PHP_DS_ME(Vector, getIterator) 309 | 310 | PHP_DS_SEQUENCE_ME_LIST(Vector) 311 | PHP_DS_COLLECTION_ME_LIST(Vector) 312 | PHP_FE_END 313 | }; 314 | 315 | INIT_CLASS_ENTRY(ce, PHP_DS_NS(Vector), methods); 316 | 317 | php_ds_vector_ce = zend_register_internal_class(&ce); 318 | php_ds_vector_ce->ce_flags |= ZEND_ACC_FINAL; 319 | php_ds_vector_ce->create_object = php_ds_vector_create_object; 320 | php_ds_vector_ce->get_iterator = php_ds_vector_get_iterator; 321 | php_ds_vector_ce->serialize = php_ds_vector_serialize; 322 | php_ds_vector_ce->unserialize = php_ds_vector_unserialize; 323 | 324 | zend_declare_class_constant_long(php_ds_vector_ce, STR_AND_LEN("MIN_CAPACITY"), DS_VECTOR_MIN_CAPACITY); 325 | 326 | zend_class_implements(php_ds_vector_ce, 1, sequence_ce); 327 | php_register_vector_handlers(); 328 | } 329 | -------------------------------------------------------------------------------- /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/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/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/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_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_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_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_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/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_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/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 | -------------------------------------------------------------------------------- /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_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_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/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_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/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.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/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_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 | -------------------------------------------------------------------------------- /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_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/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/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_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/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 | -------------------------------------------------------------------------------- /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/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/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_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_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 | -------------------------------------------------------------------------------- /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/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.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_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/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/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/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/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.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/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_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 | -------------------------------------------------------------------------------- /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/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_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_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_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 | -------------------------------------------------------------------------------- /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/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_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/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/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 | -------------------------------------------------------------------------------- /test.php: -------------------------------------------------------------------------------- 1 |