├── .gitignore ├── .gitmodules ├── .travis.yml ├── README.md ├── common.h ├── config.m4 ├── php_r3.c ├── php_r3.h └── tests ├── r3_tree_compile.phpt ├── r3_tree_create.phpt ├── r3_tree_create_persist.phpt ├── r3_tree_delete_persist.phpt ├── r3_tree_insert.phpt ├── r3_tree_insert_array_callback.phpt ├── r3_tree_insert_array_callback_2.phpt ├── r3_tree_insert_dup.phpt ├── r3_tree_match.phpt └── r3_tree_store.phpt /.gitignore: -------------------------------------------------------------------------------- 1 | /modules 2 | /config.sub 3 | /config.h 4 | /config.log 5 | /config.nice 6 | /config.status 7 | /configure 8 | /configure.in 9 | /Makefile 10 | /Makefile.* 11 | /missing 12 | /install-sh 13 | /libtool 14 | /ltmain.sh 15 | /mkinstalldirs 16 | /.deps 17 | /depcomp 18 | /compile 19 | /*.lo 20 | /*.la 21 | /run-tests.php 22 | /tags 23 | /tmp-php.ini 24 | /.libs 25 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "r3"] 2 | path = r3 3 | url = https://github.com/c9s/r3.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | sudo: required 4 | 5 | php: 6 | - 5.6 7 | - 5.5 8 | 9 | compiler: 10 | - gcc 11 | 12 | env: 13 | - NO_INTERACTION=1 14 | 15 | install: 16 | - sudo apt-get update -qq 17 | - sudo apt-get install -qq automake pkg-config build-essential libtool automake autoconf m4 gnulib 18 | - sudo apt-get install -qq check libpcre3 libpcre3-dev libjemalloc-dev libjemalloc1 19 | - sudo apt-get install -qq graphviz-dev graphviz 20 | - dpkg -S libpcre3 21 | 22 | before_script: 23 | - git submodule init 24 | - git submodule update 25 | 26 | script: 27 | - phpize 28 | - ./configure --with-libdir=lib/x86_64-linux-gnu --with-pcre-dir=/usr 29 | - make 30 | - make test 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [![Build Status](https://travis-ci.org/c9s/php-r3.svg?branch=master)](https://travis-ci.org/c9s/php-r3) 4 | 5 | ## Build 6 | 7 | > Please note that `--with-pcre-dir` is required when your php is not compiled with bundled libpcre. 8 | 9 | Build on Linux: 10 | 11 | ```sh 12 | git submodule init 13 | git submodule update 14 | ./configure --enable-r3 --with-pcre-dir=/usr --with-libdir=lib/x86_64-linux-gnu 15 | make && make test 16 | make install 17 | ``` 18 | 19 | Build on OS X (Macports): 20 | 21 | ```sh 22 | git submodule init 23 | git submodule update 24 | phpize 25 | ./configure --enable-r3 --with-pcre-dir=/opt/local 26 | make clean 27 | make 28 | ``` 29 | 30 | ## Example 31 | 32 | ```php 33 | $tree = r3_tree_create_persist("app", 10); 34 | if (!r3_tree_is_compiled($tree)) { 35 | r3_tree_insert($tree, "/foo/bar", ["simplecallback"]); 36 | r3_tree_insert($tree, "/foo/zoo", ["simplecallback"]); 37 | r3_tree_insert($tree, "/hack/zzz", ["simplecallback"]); 38 | r3_tree_compile($tree); 39 | } 40 | $data = r3_tree_match($tree, "/hack/zzz"); 41 | print_r($data); 42 | ``` 43 | 44 | 45 | ```php 46 | $tree = r3_tree_create_persist("app", 10); 47 | 48 | $ret = r3_tree_insert($tree, "/foo/bar", "simplecallback"); 49 | $ret = r3_tree_insert($tree, "/foo/zoo", ["controller","simplecallback"]); 50 | $ret = r3_tree_insert($tree, "/hack/zzz", ["callable","simplecallback"]); 51 | $ret = r3_tree_compile($tree); 52 | $data = r3_tree_match($tree, "/foo/bar"); 53 | $ret = r3_tree_delete_persist("app"); 54 | ``` 55 | 56 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | #ifndef _COMMON_H 2 | #define _COMMON_H 3 | 4 | #define CLASS_ENTRY(name) uv_ce_##name 5 | 6 | #define OBJECT_HANDLER(name) object_handler_##name 7 | 8 | #define CLASS_ENTRY_FUNCTION_D(name) \ 9 | void init_uv_ce_##name(TSRMLS_D) 10 | 11 | #define CLASS_ENTRY_FUNCTION_C(name) \ 12 | init_uv_ce_##name(TSRMLS_C) 13 | 14 | #define DECLARE_CLASS_ENTRY(name) \ 15 | zend_object_handlers OBJECT_HANDLER(name); \ 16 | zend_class_entry *CLASS_ENTRY(name); \ 17 | CLASS_ENTRY_FUNCTION_D(name) 18 | 19 | #define FUNCTION_ENTRY(name) \ 20 | uv_fe_##name 21 | 22 | #define DECLARE_FUNCTION_ENTRY(name) \ 23 | static zend_function_entry FUNCTION_ENTRY(name)[] 24 | 25 | #define REGISTER_INTERNAL_CLASS(name) \ 26 | CLASS_ENTRY(name) = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC) 27 | 28 | #define REGISTER_INTERNAL_CLASS_EX(name, base) \ 29 | CLASS_ENTRY(name) = zend_register_internal_class_ex(&ce, CLASS_ENTRY(base), NULL TSRMLS_CC) 30 | 31 | #define INIT_CLASS_WITH_OBJECT_NEW(name, ns_name, create_function) \ 32 | zend_class_entry ce; \ 33 | memcpy(&OBJECT_HANDLER(name), zend_get_std_object_handlers(), sizeof(zend_object_handlers)); \ 34 | INIT_CLASS_ENTRY(ce, ns_name, FUNCTION_ENTRY(name)) 35 | 36 | #define REGISTER_CLASS_WITH_OBJECT_NEW(name, ns_name, create_function) \ 37 | INIT_CLASS_WITH_OBJECT_NEW(name, ns_name, create_function); \ 38 | REGISTER_INTERNAL_CLASS(name); \ 39 | CLASS_ENTRY(name)->create_object = create_function 40 | 41 | #define EXTENDS_CLASS_WITH_OBJECT_NEW(name, ns_name, create_function, base) \ 42 | INIT_CLASS_WITH_OBJECT_NEW(name, ns_name, create_function); \ 43 | REGISTER_INTERNAL_CLASS_EX(name, base); \ 44 | CLASS_ENTRY(name)->create_object = create_function 45 | 46 | #define REGISTER_CLASS(name, ns_name) \ 47 | zend_class_entry ce; \ 48 | INIT_CLASS_ENTRY(ce, ns_name, FUNCTION_ENTRY(name)); \ 49 | REGISTER_INTERNAL_CLASS(name) 50 | 51 | #define EXTENDS_CLASS(name, ns_name, base) \ 52 | zend_class_entry ce; \ 53 | INIT_CLASS_ENTRY(ce, ns_name, FUNCTION_ENTRY(name)); \ 54 | REGISTER_INTERNAL_CLASS_EX(name, base) 55 | 56 | #define ARGINFO(classname, method) \ 57 | arginfo_##classname##_##method 58 | 59 | #ifndef offsetof 60 | #define offsetof(s,memb) ((size_t)((char *)&((s *)0)->memb-(char *)0)) 61 | #endif 62 | 63 | #define FETCH_RESOURCE(pointer, type) (type *) (pointer - offsetof(type, zo)) 64 | 65 | #define FETCH_OBJECT_RESOURCE(object, type) FETCH_RESOURCE(zend_object_store_get_object(object TSRMLS_CC), type) 66 | 67 | #define REGISTER_CLASS_CONSTANT_LONG(class, name) \ 68 | zend_declare_class_constant_long(CLASS_ENTRY(class), ZEND_STRL(#name), name TSRMLS_CC) 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | dnl vim:sw=2:ts=2:sts=2: 2 | AC_PROG_CC 3 | AC_PROG_CC_STDC 4 | AC_FUNC_VPRINTF 5 | AC_CHECK_FUNCS([gettimeofday memset strchr strdup strndup strstr]) 6 | 7 | 8 | PHP_ARG_ENABLE(r3, whether to enable r3 support, 9 | Make sure that the comment is aligned: 10 | [ --enable-r3 Enable r3 support]) 11 | 12 | PHP_ARG_WITH(pcre-dir, libpcre install dir, 13 | [ --with-pcre-dir=DIR PCRE: libpcre install prefix]) 14 | 15 | if test "$PHP_R3_DEBUG" != "no"; then 16 | CFLAGS="$CFLAGS -Wall -g -ggdb -O0 -DPHP_R3_DEBUG=1" 17 | AC_DEFINE(PHP_R3_DEBUG, 1, [Enable r3 debug support]) 18 | fi 19 | 20 | if test $PHP_R3 != "no"; then 21 | r3_sources=" 22 | r3/3rdparty/zmalloc.c 23 | r3/src/str.c 24 | r3/src/token.c 25 | r3/src/slug.c 26 | r3/src/edge.c 27 | r3/src/node.c 28 | r3/src/list.c 29 | r3/src/match_entry.c" 30 | PHP_NEW_EXTENSION(r3, $r3_sources php_r3.c, $ext_shared) 31 | 32 | dnl PHP_R3_CFLAGS="-DHAVE_CONFIG_H -I@ext_srcdir@/pcrelib -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1" 33 | 34 | PHP_ADD_INCLUDE("$srcdir/r3/include") 35 | 36 | dnl include zmalloc 37 | PHP_ADD_INCLUDE("$srcdir/r3/3rdparty") 38 | 39 | dnl Add libpcre include directory 40 | PHP_ADD_INCLUDE("$phpincludedir/ext/pcre/pcrelib") 41 | 42 | AC_CHECK_DECL( 43 | [HAVE_BUNDLED_PCRE], 44 | [AC_CHECK_HEADERS( 45 | [ext/pcre/php_pcre.h], 46 | [ 47 | PHP_ADD_EXTENSION_DEP([r3], [pcre]) 48 | AC_DEFINE([ZEPHIR_USE_PHP_PCRE], [1], [Whether PHP pcre extension is present at compile time]) 49 | ], 50 | , 51 | [[#include "main/php.h"]] 52 | )],[ 53 | dnl Detect pcre 54 | if test "$PHP_PCRE_DIR" != "yes" ; then 55 | AC_MSG_CHECKING([for PCRE headers location]) 56 | for i in $PHP_PCRE_DIR $PHP_PCRE_DIR/include $PHP_PCRE_DIR/include/pcre $PHP_PCRE_DIR/local/include; do 57 | test -f $i/pcre.h && PCRE_INCDIR=$i 58 | done 59 | else 60 | AC_MSG_CHECKING([for PCRE headers location]) 61 | for i in /usr/include /usr/local/include /usr/local/include/pcre /opt/local/include; do 62 | test -f $i/pcre.h && PCRE_INCDIR=$i 63 | done 64 | fi 65 | 66 | if test -z "$PCRE_INCDIR"; then 67 | AC_MSG_ERROR([Could not find pcre.h in $PHP_PCRE_DIR]) 68 | fi 69 | AC_MSG_RESULT([PCRE Include: $PCRE_INCDIR]) 70 | 71 | 72 | AC_MSG_CHECKING([for PCRE library location]) 73 | if test "$PHP_PCRE_DIR" != "yes" ; then 74 | for j in $PHP_PCRE_DIR $PHP_PCRE_DIR/$PHP_LIBDIR; do 75 | test -f $j/libpcre.a || test -f $j/libpcre.$SHLIB_SUFFIX_NAME && PCRE_LIBDIR=$j 76 | done 77 | else 78 | for j in /usr/lib /usr/local/lib /opt/local/lib; do 79 | test -f $j/libpcre.a || test -f $j/libpcre.$SHLIB_SUFFIX_NAME && PCRE_LIBDIR=$j 80 | done 81 | fi 82 | 83 | if test -z "$PCRE_LIBDIR" ; then 84 | AC_MSG_ERROR([Could not find libpcre.(a|$SHLIB_SUFFIX_NAME) in $PHP_PCRE_DIR]) 85 | fi 86 | AC_MSG_RESULT([$PCRE_LIBDIR]) 87 | 88 | AC_DEFINE(HAVE_PCRE, 1, [ ]) 89 | PHP_ADD_INCLUDE($PCRE_INCDIR) 90 | PHP_ADD_LIBRARY_WITH_PATH(pcre, $PCRE_LIBDIR, R3_SHARED_LIBADD) 91 | 92 | 93 | 94 | ], [[#include "php_config.h"]] 95 | ) 96 | 97 | 98 | PHP_SUBST(R3_SHARED_LIBADD) 99 | fi 100 | 101 | -------------------------------------------------------------------------------- /php_r3.c: -------------------------------------------------------------------------------- 1 | #include "php_r3.h" 2 | #include "ext/standard/info.h" 3 | #include 4 | 5 | ZEND_DECLARE_MODULE_GLOBALS(r3); 6 | 7 | PHP_MINIT_FUNCTION(r3); 8 | PHP_MSHUTDOWN_FUNCTION(r3); 9 | PHP_MINFO_FUNCTION(r3); 10 | 11 | /* 12 | ZEND_BEGIN_ARG_INFO_EX(arginfo_tree_create, 0, 0, 1) 13 | ZEND_ARG_INFO(0, capacity) 14 | ZEND_END_ARG_INFO() 15 | */ 16 | 17 | 18 | /** 19 | * This function allocates a persistent zval and copy the string with pestrndup (persistent). 20 | */ 21 | void MAKE_PZVAL_STR(zval** zdata, zval * zstr) 22 | { 23 | *zdata = pemalloc(sizeof(zval), 1); 24 | Z_TYPE_PP(zdata) = Z_TYPE_P(zstr); 25 | Z_STRVAL_PP(zdata) = pestrndup(Z_STRVAL_P(zstr), Z_STRLEN_P(zstr), 1); 26 | Z_STRLEN_PP(zdata) = Z_STRLEN_P(zstr); 27 | } 28 | 29 | static const zend_function_entry r3_functions[] = { 30 | PHP_FE(r3_tree_create, NULL) 31 | PHP_FE(r3_tree_create_persist, NULL) 32 | PHP_FE(r3_tree_delete_persist, NULL) 33 | PHP_FE(r3_tree_store, NULL) 34 | PHP_FE(r3_tree_insert, NULL) 35 | PHP_FE(r3_tree_compile, NULL) 36 | PHP_FE(r3_tree_is_compiled, NULL) 37 | PHP_FE(r3_tree_match, NULL) 38 | PHP_FE_END 39 | }; 40 | 41 | 42 | #if COMPILE_DL_R3 43 | ZEND_GET_MODULE(r3) 44 | #endif 45 | 46 | zend_module_entry r3_module_entry = { 47 | #if ZEND_MODULE_API_NO >= 20010901 48 | STANDARD_MODULE_HEADER, 49 | #endif 50 | "R3", 51 | r3_functions, 52 | PHP_MINIT(r3), 53 | PHP_MSHUTDOWN(r3), 54 | NULL, 55 | NULL, 56 | PHP_MINFO(r3), 57 | #if ZEND_MODULE_API_NO >= 20010901 58 | "0.1", 59 | #endif 60 | STANDARD_MODULE_PROPERTIES 61 | }; 62 | 63 | 64 | static void php_r3_resource_persist_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) 65 | { 66 | php_r3_resource *res = (php_r3_resource*)rsrc->ptr; 67 | if (res) { 68 | if (res->node) { 69 | r3_tree_free(res->node); 70 | } 71 | pefree(res, 1); 72 | } 73 | } 74 | 75 | static void php_r3_resource_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) 76 | { 77 | php_r3_resource *res = (php_r3_resource*)rsrc->ptr; 78 | if (res) { 79 | if (res->node) { 80 | r3_tree_free(res->node); 81 | } 82 | efree(res); 83 | } 84 | } 85 | 86 | PHP_MINIT_FUNCTION(r3) { 87 | // CLASS_ENTRY_FUNCTION_C(R3); 88 | le_r3_resource = zend_register_list_destructors_ex(php_r3_resource_dtor, NULL, PHP_R3_RESOURCE_NAME, module_number); 89 | le_r3_resource_persist = zend_register_list_destructors_ex(NULL, php_r3_resource_persist_dtor, PHP_R3_RESOURCE_NAME, module_number); 90 | return SUCCESS; 91 | } 92 | 93 | PHP_MSHUTDOWN_FUNCTION(r3) { 94 | return SUCCESS; 95 | } 96 | 97 | 98 | PHP_MINFO_FUNCTION(r3) { 99 | php_info_print_table_start(); 100 | php_info_print_table_header(2, "r3 support", "enabled"); 101 | php_info_print_table_end(); 102 | // DISPLAY_INI_ENTRIES(); 103 | } 104 | 105 | PHP_FUNCTION(r3_tree_store) 106 | { 107 | char *namespace; 108 | int namespace_len; 109 | 110 | zval *zres; 111 | php_r3_resource *res; 112 | 113 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sr", 114 | &namespace, &namespace_len, &zres) == FAILURE) { 115 | RETURN_FALSE; 116 | } 117 | 118 | ZEND_FETCH_RESOURCE(res, php_r3_resource*, &zres, -1, PHP_R3_RESOURCE_NAME, le_r3_resource); 119 | 120 | // TODO store in the global 121 | 122 | RETURN_TRUE; 123 | } 124 | 125 | PHP_FUNCTION(r3_tree_create) 126 | { 127 | long capacity = 10; 128 | 129 | /* parse parameters */ 130 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &capacity) == FAILURE) { 131 | RETURN_FALSE; 132 | } 133 | 134 | php_r3_resource *res; 135 | res = emalloc(sizeof(php_r3_resource)); 136 | res->node = r3_tree_create(capacity); 137 | ZEND_REGISTER_RESOURCE(return_value, res, le_r3_resource); 138 | } 139 | 140 | PHP_FUNCTION(r3_tree_insert) 141 | { 142 | zval *zres = NULL; 143 | zval *zcallback = NULL; 144 | char *path = NULL; 145 | int path_len; 146 | php_r3_resource *res = NULL; 147 | 148 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsz", 149 | &zres, &path, &path_len, &zcallback) == FAILURE) { 150 | RETURN_FALSE; 151 | } 152 | 153 | 154 | ZEND_FETCH_RESOURCE(res, php_r3_resource*, &zres, -1, PHP_R3_RESOURCE_NAME, le_r3_resource_persist); 155 | if (res) { 156 | 157 | // copy data 158 | zval *zdata = NULL; 159 | 160 | // callable in string format 161 | if (Z_TYPE_P(zcallback) == IS_STRING) { 162 | 163 | MAKE_PZVAL_STR(&zdata, zcallback); 164 | 165 | } else if (Z_TYPE_P(zcallback) == IS_ARRAY) { 166 | 167 | // array_init 168 | 169 | zdata = pemalloc(sizeof(zval), 1); 170 | // INIT_ZVAL(zdata); 171 | Z_TYPE_P(zdata) = IS_ARRAY; 172 | Z_ARRVAL_P(zdata) = pemalloc(sizeof(HashTable), 1); 173 | zend_hash_init(Z_ARRVAL_P(zdata), 2, NULL, NULL, 1); 174 | zval **itemdata; 175 | HashTable *arr_hash = Z_ARRVAL_P(zcallback); 176 | HashPosition pointer; 177 | for(zend_hash_internal_pointer_reset_ex(arr_hash, &pointer); 178 | zend_hash_get_current_data_ex(arr_hash, (void**) &itemdata, &pointer) == SUCCESS; 179 | zend_hash_move_forward_ex(arr_hash, &pointer)) 180 | { 181 | if (Z_TYPE_PP(itemdata) != IS_STRING) { 182 | php_error(E_ERROR, "Invalid callback data type."); 183 | } 184 | 185 | // zend_hash_next_index_insert(Z_ARRVAL_P(arg), &value, sizeof(zval *), NULL); 186 | zval *zp_str = NULL; 187 | MAKE_PZVAL_STR(&zp_str, *itemdata); 188 | Z_ADDREF_P(zp_str); 189 | add_next_index_zval(zdata, zp_str); 190 | } 191 | } 192 | 193 | // zend_hash_add(&fcgi_mgmt_vars, name, name_len, &zvalue, sizeof(zvalue), NULL); 194 | 195 | // int data = 10; 196 | char *errstr = NULL; 197 | node *ret = r3_tree_insert_pathl_ex(res->node, path, path_len, NULL, (void*) zdata, &errstr); 198 | if (ret == NULL) { 199 | // failed insertion 200 | // printf("error: %s\n", errstr); 201 | // php_error(E_ERROR, errstr); 202 | free(errstr); // errstr is created from `asprintf`, so you have to free it manually. 203 | RETURN_FALSE; 204 | } 205 | RETURN_TRUE; 206 | } 207 | RETURN_FALSE; 208 | } 209 | 210 | 211 | PHP_FUNCTION(r3_tree_match) 212 | { 213 | zval *zres = NULL; 214 | char *path = NULL; 215 | int path_len; 216 | php_r3_resource *res = NULL; 217 | 218 | 219 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &zres, &path, &path_len) == FAILURE) { 220 | RETURN_FALSE; 221 | } 222 | ZEND_FETCH_RESOURCE(res, php_r3_resource*, &zres, -1, PHP_R3_RESOURCE_NAME, le_r3_resource_persist); 223 | 224 | node *matched_node = NULL; 225 | if (res) { 226 | matched_node = r3_tree_matchl(res->node, path, path_len, NULL); 227 | if (matched_node) { 228 | zval *retzval = (zval*) matched_node->data; 229 | RETURN_ZVAL(retzval, 1, 0); 230 | } 231 | RETURN_FALSE; 232 | } 233 | RETURN_FALSE; 234 | } 235 | 236 | 237 | PHP_FUNCTION(r3_tree_is_compiled) 238 | { 239 | zval *zres = NULL; 240 | php_r3_resource *res = NULL; 241 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) { 242 | RETURN_FALSE; 243 | } 244 | ZEND_FETCH_RESOURCE(res, php_r3_resource*, &zres, -1, PHP_R3_RESOURCE_NAME, le_r3_resource_persist); 245 | if (res && res->compiled) { 246 | RETURN_TRUE; 247 | } 248 | RETURN_FALSE; 249 | } 250 | 251 | 252 | PHP_FUNCTION(r3_tree_compile) 253 | { 254 | zval *zres = NULL; 255 | php_r3_resource *res = NULL; 256 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zres) == FAILURE) { 257 | RETURN_FALSE; 258 | } 259 | 260 | ZEND_FETCH_RESOURCE(res, php_r3_resource*, &zres, -1, PHP_R3_RESOURCE_NAME, le_r3_resource_persist); 261 | if (!res) { 262 | RETURN_FALSE; 263 | } 264 | 265 | char *errstr = NULL; 266 | int err = r3_tree_compile(res->node, &errstr); 267 | if (err != 0) { 268 | // fail 269 | // printf("error: %s\n", errstr); 270 | free(errstr); // errstr is created from `asprintf`, so you have to free it manually. 271 | // php_error(E_ERROR, estrdup(errstr)); 272 | RETURN_FALSE; 273 | } 274 | res->compiled = true; 275 | RETURN_TRUE; 276 | } 277 | 278 | PHP_FUNCTION(r3_tree_create_persist) 279 | { 280 | long capacity = 10; 281 | char *namespace; 282 | int namespace_len; 283 | 284 | zend_rsrc_list_entry *le; 285 | 286 | /* parse parameters */ 287 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", 288 | &namespace, &namespace_len, &capacity) == FAILURE) { 289 | RETURN_FALSE; 290 | } 291 | 292 | 293 | char *key; 294 | int key_len = spprintf(&key, 0, "r3_%s", namespace); 295 | if (zend_hash_find(&EG(persistent_list), key, key_len + 1, (void**) &le) == SUCCESS) { 296 | ZEND_REGISTER_RESOURCE(return_value, le->ptr, le_r3_resource_persist); 297 | efree(key); 298 | return; 299 | } 300 | 301 | php_r3_resource *res; 302 | res = pemalloc(sizeof(php_r3_resource), 1); 303 | res->compiled = false; 304 | res->node = r3_tree_create(capacity); 305 | ZEND_REGISTER_RESOURCE(return_value, res, le_r3_resource_persist); 306 | 307 | 308 | zend_rsrc_list_entry new_le; 309 | new_le.ptr = res; 310 | Z_TYPE(new_le) = le_r3_resource_persist; 311 | if (zend_hash_update(&EG(persistent_list), key, key_len + 1, (void*) &new_le, sizeof(zend_rsrc_list_entry), NULL) == FAILURE) { 312 | RETURN_FALSE; 313 | } 314 | efree(key); 315 | } 316 | 317 | PHP_FUNCTION(r3_tree_delete_persist) 318 | { 319 | char *namespace; 320 | int namespace_len; 321 | 322 | zend_rsrc_list_entry *le; 323 | 324 | /* parse parameters */ 325 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", 326 | &namespace, &namespace_len) == FAILURE) { 327 | RETURN_FALSE; 328 | } 329 | 330 | 331 | char *key; 332 | int key_len = spprintf(&key, 0, "r3_%s", namespace); 333 | if (zend_hash_find(&EG(persistent_list), key, key_len + 1, (void**) &le) == SUCCESS) { 334 | // ZEND_REGISTER_RESOURCE(return_value, le->ptr, le_r3_resource_persist); 335 | // zend_list_delete(Z_LVAL_P(zperson)); 336 | zend_hash_del(&EG(persistent_list), key, key_len + 1); 337 | efree(key); 338 | RETURN_TRUE; 339 | } 340 | efree(key); 341 | RETURN_TRUE; 342 | } 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | -------------------------------------------------------------------------------- /php_r3.h: -------------------------------------------------------------------------------- 1 | #ifndef _PHP_R3_H 2 | #define _PHP_R3_H 3 | #ifdef HAVE_CONFIG_H 4 | #include "config.h" 5 | #endif 6 | 7 | #ifdef ZTS 8 | #include 9 | #endif 10 | 11 | #include 12 | #include 13 | #include "common.h" 14 | 15 | extern zend_module_entry r3_module_entry; 16 | 17 | typedef struct _php_r3_resource { 18 | node *node; 19 | bool compiled; 20 | char * namespace; 21 | int namespace_len; 22 | } php_r3_resource; 23 | 24 | #define PHP_R3_RESOURCE_NAME "R3 Tree" 25 | int le_r3_resource; 26 | int le_r3_resource_persist; 27 | 28 | // DECLARE_CLASS_ENTRY(R3); 29 | 30 | PHP_FUNCTION(r3_tree_insert); 31 | PHP_FUNCTION(r3_tree_create); 32 | PHP_FUNCTION(r3_tree_create_persist); 33 | PHP_FUNCTION(r3_tree_delete_persist); 34 | PHP_FUNCTION(r3_tree_store); 35 | PHP_FUNCTION(r3_tree_compile); 36 | PHP_FUNCTION(r3_tree_is_compiled); 37 | PHP_FUNCTION(r3_tree_match); 38 | 39 | // global variable structure 40 | ZEND_BEGIN_MODULE_GLOBALS(r3) 41 | // zval *mux_array; 42 | // HashTable * persistent_list; 43 | // zend_bool direction; 44 | ZEND_END_MODULE_GLOBALS(r3) 45 | 46 | 47 | #ifdef ZTS 48 | #define R3_G(v) TSRMG(r3_globals_id, zend_r3_globals *, v) 49 | #else 50 | #define R3_G(v) (r3_globals.v) 51 | #endif 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /tests/r3_tree_compile.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check r3_tree_compile 3 | --FILE-- 4 |