diff --git a/php_ketama/ketama.c b/php_ketama/ketama.c
index b8cb3da..a82fad1 100644
--- a/php_ketama/ketama.c
+++ b/php_ketama/ketama.c
@@ -25,6 +25,7 @@
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
+#include "pecl-compat/compat.h"
#include "php_ketama.h"
#include "ketama.h"
@@ -33,10 +34,9 @@ ZEND_DECLARE_MODULE_GLOBALS(ketama)
*/
/* True global resources - no need for thread safety here */
-static int le_ketama;
static int le_ketama_continuum;
-static void ketama_continuum_dtor( zend_rsrc_list_entry *rsrc TSRMLS_DC )
+static void ketama_continuum_dtor( zend_resource *rsrc TSRMLS_DC )
{
ketama_continuum continuum = (ketama_continuum)rsrc->ptr;
ketama_smoke( continuum );
@@ -164,7 +164,7 @@ PHP_MINFO_FUNCTION(ketama)
PHP_FUNCTION(ketama_roll)
{
char *filename;
- long filename_len;
+ COMPAT_ARG_SIZE_T filename_len;
if ( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len ) == FAILURE )
{
@@ -174,7 +174,7 @@ PHP_FUNCTION(ketama_roll)
ketama_continuum c;
if ( ketama_roll( &c, filename ) )
{
- ZEND_REGISTER_RESOURCE( return_value, c, le_ketama_continuum );
+ compat_zend_register_resource(return_value, c, le_ketama_continuum TSRMLS_DC);
} else {
php_error_docref(NULL TSRMLS_CC, E_ERROR, "unable to create Ketama continuum: %s", ketama_error());
}
@@ -194,8 +194,12 @@ PHP_FUNCTION(ketama_destroy)
return;
}
- ZEND_FETCH_RESOURCE( continuum, ketama_continuum, &r, -1, "ketama continuum", le_ketama_continuum );
- zend_list_delete( Z_LVAL_P( r ) );
+ continuum = (ketama_continuum) compat_zend_fetch_resource(r, "ketama continuum", le_ketama_continuum TSRMLS_CC);
+ if (continuum == NULL) {
+ return;
+ }
+
+ compat_zend_delete_resource(r TSRMLS_CC);
}
/* }}} */
@@ -212,7 +216,11 @@ PHP_FUNCTION(ketama_print_continuum)
return;
}
- ZEND_FETCH_RESOURCE( continuum, ketama_continuum, &r, -1, "ketama continuum", le_ketama_continuum );
+ continuum = (ketama_continuum) compat_zend_fetch_resource(r, "ketama continuum", le_ketama_continuum TSRMLS_CC);
+ if (continuum == NULL) {
+ return;
+ }
+
ketama_print_continuum( continuum );
}
/* }}} */
@@ -222,7 +230,7 @@ PHP_FUNCTION(ketama_print_continuum)
Prints the latest ketama error */
PHP_FUNCTION(ketama_error)
{
- RETURN_STRING( (char *)ketama_error(), 1 );
+ RETURN_STRING((char *)ketama_error());
}
/* }}} */
@@ -234,7 +242,7 @@ PHP_FUNCTION(ketama_get_server)
zval *zcontinuum;
ketama_continuum continuum;
char *key;
- long key_len;
+ COMPAT_ARG_SIZE_T key_len;
mcs* server;
if ( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "sr", &key, &key_len, &zcontinuum ) == FAILURE )
@@ -242,12 +250,16 @@ PHP_FUNCTION(ketama_get_server)
return;
}
- ZEND_FETCH_RESOURCE( continuum, ketama_continuum, &zcontinuum, -1, "ketama continuum", le_ketama_continuum );
+ continuum = (ketama_continuum) compat_zend_fetch_resource(zcontinuum, "ketama continuum", le_ketama_continuum TSRMLS_CC);
+ if (continuum == NULL) {
+ return;
+ }
+
server = ketama_get_server( key, continuum );
array_init( return_value );
add_assoc_long( return_value, "point", server->point );
- add_assoc_string( return_value, "ip", server->ip, 1 );
+ add_assoc_string( return_value, "ip", server->ip );
}
/* }}} */
diff --git a/php_ketama/pecl-compat/LICENSE b/php_ketama/pecl-compat/LICENSE
new file mode 100644
index 0000000..e0bc44c
--- /dev/null
+++ b/php_ketama/pecl-compat/LICENSE
@@ -0,0 +1,68 @@
+--------------------------------------------------------------------
+ The PHP License, version 3.01
+Copyright (c) 1999 - 2016 The PHP Group. All rights reserved.
+--------------------------------------------------------------------
+
+Redistribution and use in source and binary forms, with or without
+modification, is permitted provided that the following conditions
+are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ 3. The name "PHP" must not be used to endorse or promote products
+ derived from this software without prior written permission. For
+ written permission, please contact group@php.net.
+
+ 4. Products derived from this software may not be called "PHP", nor
+ may "PHP" appear in their name, without prior written permission
+ from group@php.net. You may indicate that your software works in
+ conjunction with PHP by saying "Foo for PHP" instead of calling
+ it "PHP Foo" or "phpfoo"
+
+ 5. The PHP Group may publish revised and/or new versions of the
+ license from time to time. Each version will be given a
+ distinguishing version number.
+ Once covered code has been published under a particular version
+ of the license, you may always continue to use it under the terms
+ of that version. You may also choose to use such covered code
+ under the terms of any subsequent version of the license
+ published by the PHP Group. No one other than the PHP Group has
+ the right to modify the terms applicable to covered code created
+ under this License.
+
+ 6. Redistributions of any form whatsoever must retain the following
+ acknowledgment:
+ "This product includes PHP software, freely available from
+ ".
+
+THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
+ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
+DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------
+
+This software consists of voluntary contributions made by many
+individuals on behalf of the PHP Group.
+
+The PHP Group can be contacted via Email at group@php.net.
+
+For more information on the PHP Group and the PHP project,
+please see .
+
+PHP includes the Zend Engine, freely available at
+.
diff --git a/php_ketama/pecl-compat/README.md b/php_ketama/pecl-compat/README.md
new file mode 100644
index 0000000..c76ed89
--- /dev/null
+++ b/php_ketama/pecl-compat/README.md
@@ -0,0 +1,33 @@
+The PECL compatibility library is a set of C include files whose objective is to minimize the pain of making a PHP extension compatible with PHP 5 and 7.
+
+Project home : [https://github.com/flaupretre/pecl-compat](https://github.com/flaupretre/pecl-compat)
+
+# Main features
+
+- A set of miscellaneous compatibility macros,
+
+- A backport of the *zend_string* functions and macros to PHP 5,
+
+- A backport of most PHP 7 *zend_hash* features to PHP 5.
+
+- A compatibility library for simple resource handling
+
+# Examples
+
+For examples of using this library, look at the [PCS extension](https://github.com/flaupretre/pecl-pcs). There, you will see usage examples of most *pecl-compat* features.
+
+# Usage
+
+Using the library is simple. Download the latest release from the [github repository](https://github.com/flaupretre/pecl-compat/releases) and insert it a new subdirectory inside your code tree. Then, include the 'compat.h' file in every '.c' source file.
+
+# History
+
+I first tried to port the [PHK](http://pecl.php.net/package/phk) extension to PHP 7 using raw '#ifdef' directives. Unfortunately, it quickly became clear that it was not possible without making the code totally unreadable. For pure 'bridge' extensions, it may be possible. But, as soon as you make use of hash tables and strings, your code quicly becomes very hard to maintain.
+
+Then, I explored other solutions : separate branches, duplicate code trees... without finding one I would be satisfied with, mostly because all these solutions bring their own set of maintainability issues : separate branches bring a huge versioning problem, and separate code trees are a maintenance headache in the long term. As PHP 5 modules will probably need to be maintained during years, none of these solutions looked convincing to me.
+
+So, I reverted to the solution of keeping a single source tree and move most of my conditional code to a reusable compatibility layer. In order to benefit of the PHP 7 performance increase, most pecl-compat features are PHP 7 features backported to PHP 5. PHP 7 generally calls the underlying PHP functions directly, with the same performance as a pure-PHP7 development. So, when adapting your extension to use pecl-compat, you will, at the same time, change your code to use new PHP 7 features and make it compatible with both PHP 5 & 7. As a side effect, this makes it easier to discard PHP 5 compatibility in the future, when time has come.
+
+# Supported PHP versions
+
+5.3 and above.
diff --git a/php_ketama/pecl-compat/compat.h b/php_ketama/pecl-compat/compat.h
new file mode 100644
index 0000000..3d5cd0f
--- /dev/null
+++ b/php_ketama/pecl-compat/compat.h
@@ -0,0 +1,109 @@
+/*
+ +----------------------------------------------------------------------+
+ | Compatibility macros for different PHP versions |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2015 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Francois Laupretre |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef _COMPAT_H
+#define _COMPAT_H
+
+#define PECL_COMPAT_VERSION 1.3
+
+#include
+#include
+#include
+
+#include "php.h"
+#include "zend.h"
+#include "zend_extensions.h"
+#include "zend_API.h"
+
+#define PHP_5_0_X_API_NO 220040412
+#define PHP_5_1_X_API_NO 220051025
+#define PHP_5_2_X_API_NO 220060519
+#define PHP_5_3_X_API_NO 220090626
+#define PHP_5_4_X_API_NO 220100525
+#define PHP_5_5_X_API_NO 220121212
+#define PHP_5_6_X_API_NO 220131226
+
+#if PHP_MAJOR_VERSION >= 7
+# define PHP_7
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if HAVE_STRING_H
+# include
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include
+#endif
+
+#ifdef PHP_WIN32
+# include "win32/time.h"
+#elif defined(NETWARE)
+# include
+# include
+#else
+# include
+#endif
+
+#ifdef HAVE_SYS_RESOURCE_H
+# include
+#endif
+
+#ifdef HAVE_STDARG_H
+#include
+#endif
+
+#ifdef HAVE_STDLIB_H
+# include
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+# include
+#endif
+
+#ifdef PHP_WIN32
+#include
+#else
+#include
+#endif
+
+#if ZEND_EXTENSION_API_NO >= PHP_5_6_X_API_NO
+#include "zend_virtual_cwd.h"
+#else
+#include "TSRM/tsrm_virtual_cwd.h"
+#endif
+
+#ifdef PHP_7
+#include "Zend/zend_portability.h"
+#endif
+
+/*-- Include submodules */
+
+#include "src/misc.h"
+#include "src/zend_string.h"
+#include "src/zend_hash.h"
+#include "src/zend_resource.h"
+
+#endif /* _COMPAT_H */
diff --git a/php_ketama/pecl-compat/src/misc.h b/php_ketama/pecl-compat/src/misc.h
new file mode 100644
index 0000000..e7e8dfb
--- /dev/null
+++ b/php_ketama/pecl-compat/src/misc.h
@@ -0,0 +1,253 @@
+/*
+ +----------------------------------------------------------------------+
+ | Compatibility between PHP versions |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2015 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Francois Laupretre |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef __PECL_COMPAT_MISC_H
+#define __PECL_COMPAT_MISC_H 1
+
+#ifdef PHP_7
+/*============================================================================*/
+
+typedef zend_string * OPENED_PATH_PTR; /* Type of stream opened_path argument */
+typedef size_t COMPAT_ARG_SIZE_T; /* Size of string arguments */
+typedef zend_long COMPAT_ARG_LONG_T; /* Type of long (integer) arguments */
+
+#define compat_zval_ptr_dtor(zp) zval_ptr_dtor(zp)
+
+#else
+/*== PHP 5 ===================================================================*/
+
+typedef char * OPENED_PATH_PTR;
+typedef off_t zend_off_t;
+typedef int COMPAT_ARG_SIZE_T;
+typedef long COMPAT_ARG_LONG_T;
+typedef long zend_long;
+
+#define compat_zval_ptr_dtor(zp) zval_dtor(zp)
+
+#endif
+/*============================================================================*/
+
+#ifndef MIN
+# define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef MAX
+# define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+/*---------------------------------------------------------------*/
+/* (Taken from pcre/pcrelib/internal.h) */
+/* To cope with SunOS4 and other systems that lack memmove() but have bcopy(),
+define a macro for memmove() if HAVE_MEMMOVE is false, provided that HAVE_BCOPY
+is set. Otherwise, include an emulating function for those systems that have
+neither (there are some non-Unix environments where this is the case). This
+assumes that all calls to memmove are moving strings upwards in store,
+which is the case in this extension. */
+
+#if ! HAVE_MEMMOVE
+# ifdef memmove
+# undef memmove /* some systems may have a macro */
+# endif
+# if HAVE_BCOPY
+# define memmove(a, b, c) bcopy(b, a, c)
+# else
+ static void *my_memmove(unsigned char *dest, const unsigned char *src,
+ size_t n)
+ {
+ int i;
+
+ dest += n;
+ src += n;
+ for (i = 0; i < n; ++i)
+ *(--dest) = *(--src);
+ }
+# define memmove(a, b, c) my_memmove(a, b, c)
+# endif /* not HAVE_BCOPY */
+#endif /* not HAVE_MEMMOVE */
+
+#ifdef _AIX
+# undef PHP_SHLIB_SUFFIX
+# define PHP_SHLIB_SUFFIX "a"
+#endif
+
+#ifndef ZVAL_IS_ARRAY
+#define ZVAL_IS_ARRAY(zp) (Z_TYPE_P((zp))==IS_ARRAY)
+#endif
+
+#ifndef ZVAL_IS_STRING
+#define ZVAL_IS_STRING(zp) (Z_TYPE_P((zp))==IS_STRING)
+#endif
+
+#ifndef ZVAL_IS_LONG
+#define ZVAL_IS_LONG(zp) (Z_TYPE_P((zp))==IS_LONG)
+#endif
+
+#ifndef ZVAL_IS_BOOL
+#define ZVAL_IS_BOOL(zp) (Z_TYPE_P((zp))==IS_BOOL)
+#endif
+
+#ifndef INIT_ZVAL
+#define INIT_ZVAL(z) memset(&z, 0, sizeof(z))
+#endif
+
+#ifndef ZVAL_UNDEF
+#define ZVAL_UNDEF(z) INIT_ZVAL(*(z))
+#endif
+
+#ifndef MAKE_STD_ZVAL
+#define MAKE_STD_ZVAL(zp) { zp = emalloc(sizeof(zval)); INIT_ZVAL(*zp); }
+#endif
+
+#ifndef ALLOC_INIT_ZVAL
+#define ALLOC_INIT_ZVAL(zp) MAKE_STD_ZVAL(zp)
+#endif
+
+#ifndef ZEND_ASSUME
+#if defined(ZEND_WIN32) && !defined(__clang__)
+# define ZEND_ASSUME(c) __assume(c)
+#else
+# define ZEND_ASSUME(c)
+#endif
+#endif
+
+#ifndef ZEND_ASSERT
+#if ZEND_DEBUG
+# define ZEND_ASSERT(c) assert(c)
+#else
+# define ZEND_ASSERT(c) ZEND_ASSUME(c)
+#endif
+#endif
+
+#ifndef EMPTY_SWITCH_DEFAULT_CASE
+/* Only use this macro if you know for sure that all of the switches values
+ are covered by its case statements */
+#if ZEND_DEBUG
+# define EMPTY_SWITCH_DEFAULT_CASE() default: ZEND_ASSERT(0); break;
+#else
+# define EMPTY_SWITCH_DEFAULT_CASE() default: ZEND_ASSUME(0); break;
+#endif
+#endif
+
+#ifndef ZEND_IGNORE_VALUE
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define ZEND_IGNORE_VALUE(x) (({ __typeof__ (x) __x = (x); (void) __x; }))
+#else
+# define ZEND_IGNORE_VALUE(x) ((void) (x))
+#endif
+#endif
+
+#if PHP_API_VERSION >= 20100412
+ typedef size_t PHP_ESCAPE_HTML_ENTITIES_SIZE;
+#else
+ typedef int PHP_ESCAPE_HTML_ENTITIES_SIZE;
+#endif
+
+/* Avoid a warning when compiling stream wrapper declarations for
+ openfile/opendir/url_stat */
+
+#if ZEND_EXTENSION_API_NO >= PHP_5_6_X_API_NO
+# define COMPAT_STREAM_CONST_DECL const
+#else
+# define COMPAT_STREAM_CONST_DECL
+#endif
+
+#ifndef ZEND_MODULE_GLOBALS_ACCESSOR
+# ifdef ZTS
+# define ZEND_MODULE_GLOBALS_ACCESSOR(module_name, v) \
+ TSRMG(module_name##_globals_id, zend_##module_name##_globals *, v)
+# else
+# define ZEND_MODULE_GLOBALS_ACCESSOR(module_name, v) \
+ (module_name##_globals.v)
+# endif
+#endif
+
+#ifndef ZEND_MODULE_GLOBALS_BULK
+# ifdef ZTS
+# define ZEND_MODULE_GLOBALS_BULK(module_name) \
+ ((zend_##module_name##_globals *) \
+ (*((void ***) tsrm_ls))[module_name##_globals_id - 1])
+# else
+# define ZEND_MODULE_GLOBALS_BULK(module_name) \
+ (&module_name##_globals)
+# endif
+#endif
+
+#ifndef ZEND_TSRMLS_CACHE_DEFINE
+# define ZEND_TSRMLS_CACHE_DEFINE()
+#endif
+
+#ifndef ZEND_TSRMLS_CACHE_UPDATE
+# define ZEND_TSRMLS_CACHE_UPDATE()
+#endif
+
+#ifndef PHP_FE_END
+# define PHP_FE_END { NULL, NULL, NULL }
+#endif
+
+#ifndef ZEND_MOD_END
+ /* for php < 5.3.7 */
+# define ZEND_MOD_END {NULL, NULL, NULL}
+#endif
+
+/*============================================================================*/
+/* Duplicate a memory buffer */
+/* Supports zero size (allocates 1 byte) */
+
+static zend_always_inline void *_compat_dup(const void *ptr, size_t size, int persistent)
+{
+ char *p;
+
+ if (!ptr) return NULL;
+ if (size) {
+ p = pemalloc(size, persistent);
+ memmove(p, ptr, size);
+ } else {
+ p = pemalloc(1,persistent);
+ (*p) = '\0'; /* Ensures deterministic behavior */
+ }
+
+ return p;
+}
+
+/*---------------------------------------------------------------*/
+/* Duplicate a string and set terminating null.
+ Input string does not have to be null-terminated */
+
+static zend_always_inline void *_compat_dup_str(const void *ptr, size_t size, int persistent)
+{
+ char *p;
+
+ if (!ptr) return NULL;
+
+ p = pemalloc(size + 1, persistent);
+ if (size) memmove(p, ptr, size);
+ p[size] = '\0';
+ return p;
+}
+
+/*-----------------------------------------------------*/
+/* Fatal error - display message and abort process */
+
+static zend_always_inline void compat_unsupported(char *msg)
+{
+ php_error(E_CORE_ERROR, "This feature is not supported in this environment : %s", msg);
+ exit(1);
+}
+
+/*============================================================================*/
+#endif /* __PECL_COMPAT_MISC_H */
diff --git a/php_ketama/pecl-compat/src/zend_hash.h b/php_ketama/pecl-compat/src/zend_hash.h
new file mode 100644
index 0000000..4947e47
--- /dev/null
+++ b/php_ketama/pecl-compat/src/zend_hash.h
@@ -0,0 +1,384 @@
+/*
+ +----------------------------------------------------------------------+
+ | zend_hash compatibility layer for PHP 5 & 7 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2005-2007 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Francois Laupretre |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef _COMPAT_ZEND_HASH_H
+#define _COMPAT_ZEND_HASH_H
+
+#include "zend_hash.h"
+
+#ifdef PHP_7
+/*============================================================================*/
+
+#define compat_zend_hash_exists(ht, key) zend_hash_exists(ht, key)
+
+#define compat_zend_hash_str_exists(ht, str, len) zend_hash_str_exists(ht, str, len)
+
+#define COMPAT_HASH_PTR(_zp) (&(Z_PTR_P(_zp)))
+
+/*---------*/
+/* Changes from original version:
+ - If numeric key, returned (zend_string *) is set to NULL.
+ - If non null, returned zend_string must be released.
+*/
+static zend_always_inline int compat_zend_hash_get_current_key_ex(const HashTable *ht
+ , zend_string **str_index, zend_ulong *num_index, HashPosition *pos)
+{
+ int status;
+
+ if (str_index) (*str_index) = NULL;
+ status = zend_hash_get_current_key_ex(ht, str_index, num_index, pos);
+ if (*str_index) zend_string_addref(*str_index);
+ return status;
+}
+
+/*---------*/
+/* Added - This function is equivalent to the PHP 5 version of
+ zend_hash_get_current_key_ex() */
+
+static zend_always_inline int compat_zend_hash_str_get_current_key_ex(const HashTable *ht
+ , char **str_index, size_t *str_length, zend_ulong *num_index
+ , zend_bool duplicate, HashPosition *pos)
+{
+ int status;
+ zend_string *zp;
+
+ zp = NULL;
+ status = zend_hash_get_current_key_ex(ht, &zp, num_index, pos);
+ if (zp) {
+ if (duplicate) {
+ (*str_index) = estrndup(ZSTR_VAL(zp), ZSTR_LEN(zp));
+ } else {
+ (*str_index) = ZSTR_VAL(zp);
+ }
+ (*str_length) = ZSTR_LEN(zp);
+ }
+ return status;
+}
+
+/*---------*/
+
+static zend_always_inline void *compat_zend_hash_get_current_data_ptr_ex(HashTable *ht
+ , HashPosition *pos)
+{
+ zval *zp;
+
+ zp = zend_hash_get_current_data_ex(ht, pos);
+ return Z_PTR_P(zp);
+}
+
+#define compat_zend_hash_get_current_data_ptr(ht) \
+ compat_zend_hash_get_current_data_ptr_ex(ht, &(ht)->nInternalPointer)
+
+/*---------*/
+
+static zend_always_inline void *compat_zend_hash_get_current_data_ex(HashTable *ht
+ , HashPosition *pos)
+{
+ return (void *)zend_hash_get_current_data_ex(ht, pos);
+}
+
+#define compat_zend_hash_get_current_data(ht) \
+ compat_zend_hash_get_current_data_ex(ht, &(ht)->nInternalPointer)
+
+#define compat_zend_hash_get_current_zval_ex(ht, pos) \
+ (zval *)compat_zend_hash_get_current_data_ex(ht, pos)
+
+#define compat_zend_hash_get_current_zval(ht) \
+ compat_zend_hash_get_current_zval_ex(ht, &(ht)->nInternalPointer)
+
+#else
+/*= PHP 5 ====================================================================*/
+
+#ifndef HASH_KEY_NON_EXISTENT
+#define HASH_KEY_NON_EXISTENT HASH_KEY_NON_EXISTANT
+#endif
+
+#define COMPAT_HASH_PTR(_zp) (_zp)
+
+/*------------------------------------------------*/
+
+static zend_always_inline void *zend_hash_add_ptr(HashTable *ht
+ , zend_string *key, void *pData)
+{
+ int status;
+
+ status = zend_hash_quick_add(ht, ZSTR_VAL(key), (uint)(ZSTR_LEN(key) + 1)
+ , (ulong)ZSTR_HASH(key), &pData, sizeof(void *), NULL);
+ return (status == SUCCESS ? pData : NULL);
+}
+
+#define zend_hash_add_new_ptr(ht, key, pData) zend_hash_add_ptr(ht, key, pData)
+
+#define zend_hash_add_mem(ht, key, pData, size) \
+ zend_hash_add_ptr(ht, key, _compat_dup(pData, size, ht->persistent))
+
+/*---------*/
+
+static zend_always_inline void *zend_hash_str_add_ptr(HashTable *ht
+ , const char *str, size_t len, void *pData)
+{
+ int status;
+ char *strn = _compat_dup_str(str, len, 0);
+
+ status = zend_hash_add(ht, strn, len + 1, &pData, sizeof(void *), NULL);
+ efree(strn);
+ return (status == SUCCESS ? pData : NULL);
+}
+
+#define zend_hash_str_add_new_ptr(ht, str, len, pData) zend_hash_str_add_ptr(ht, str, len, pData)
+
+#define zend_hash_str_add_mem(ht, str, len, pData, size) \
+ zend_hash_str_add_ptr(ht, str, len, _compat_dup(pData, size, ht->persistent))
+
+/*---------*/
+
+static zend_always_inline void *zend_hash_index_add_ptr(HashTable *ht
+ , zend_ulong h, void *pData)
+{
+ int status;
+
+ status = zend_hash_index_update(ht, (ulong)h, &pData, sizeof(void *), NULL);
+ return (status == SUCCESS ? pData : NULL);
+}
+
+#define zend_hash_index_add_new_ptr(ht, h, pData) \
+ zend_hash_index_add_ptr(ht, h, pData)
+
+#define zend_hash_index_add_mem(ht, h, pData, size) \
+ zend_hash_index_add_ptr(ht, h, _compat_dup(pData, size, ht->persistent))
+
+/*---------*/
+
+static zend_always_inline void *zend_hash_next_index_insert_ptr(HashTable *ht
+ , void *pData)
+{
+ int status;
+
+ status = zend_hash_next_index_insert(ht, &pData, sizeof(void *), NULL);
+ return (status == SUCCESS ? pData : NULL);
+}
+
+#define zend_hash_next_index_insert_mem(ht, pData, size) \
+ zend_hash_next_index_insert_ptr(ht, _compat_dup(pData, size, ht->persistent))
+
+/*---------*/
+
+static zend_always_inline void *zend_hash_update_ptr(HashTable *ht
+ , zend_string *key, void *pData)
+{
+ int status;
+
+ status = zend_hash_quick_update(ht, ZSTR_VAL(key), (uint)(ZSTR_LEN(key) + 1)
+ , (ulong)ZSTR_HASH(key), &pData, sizeof(void *), NULL);
+ return (status == SUCCESS ? pData : NULL);
+}
+
+#define zend_hash_update_mem(ht, key, pData, size) \
+ zend_hash_update_ptr(ht, key, _compat_dup(pData, size, ht->persistent))
+
+/*---------*/
+
+static zend_always_inline void *zend_hash_str_update_ptr(HashTable *ht
+ , const char *str, size_t len, void *pData)
+{
+ int status;
+ char *strn = _compat_dup_str(str, len, 0);
+
+ status = zend_hash_update(ht, strn, len + 1, &pData, sizeof(void *), NULL);
+ efree(strn);
+ return (status == SUCCESS ? pData : NULL);
+}
+
+#define zend_hash_str_upate_mem(ht, str, len, pData, size) \
+ zend_hash_str_update_ptr(ht, str, len, _compat_dup(pData, size, ht->persistent))
+
+#define zend_hash_index_update_ptr(ht, h, pData) \
+ zend_hash_index_add_ptr(ht, h, pData)
+
+#define zend_hash_index_update_mem(ht, h, pData, size) \
+ zend_hash_index_add_mem(ht, h, pData, size)
+
+/*---------*/
+
+static zend_always_inline void *zend_hash_find_ptr(const HashTable *ht
+ , zend_string *key)
+{
+ int status;
+ void **p;
+
+ status = zend_hash_quick_find(ht, ZSTR_VAL(key), (uint)(ZSTR_LEN(key) + 1)
+ , (ulong)ZSTR_HASH(key), (void **)(&p));
+ return (status == SUCCESS ? (*p) : NULL);
+}
+
+/*---------*/
+
+static zend_always_inline void *zend_hash_str_find_ptr(const HashTable *ht
+ , const char *str, size_t len)
+{
+ int status;
+ void **p;
+ char *strn = _compat_dup_str(str, len, 0);
+
+ status = zend_hash_find(ht, strn, len + 1, (void **)(&p));
+ efree(strn);
+ return (status == SUCCESS ? (*p) : NULL);
+}
+
+/*---------*/
+
+static zend_always_inline void *zend_hash_index_find_ptr(const HashTable *ht
+ , zend_ulong h)
+{
+ int status;
+ void **p;
+
+ status = zend_hash_index_find(ht, h, (void **)(&p));
+ return (status == SUCCESS ? (*p) : NULL);
+}
+
+/*---------*/
+
+static zend_always_inline zend_bool compat_zend_hash_exists(const HashTable *ht
+ , zend_string *key)
+{
+ return zend_hash_quick_exists(ht, ZSTR_VAL(key), (uint)(ZSTR_LEN(key) + 1)
+ , (ulong)ZSTR_HASH(key));
+}
+
+/*---------*/
+
+static zend_always_inline zend_bool compat_zend_hash_str_exists(const HashTable *ht
+ , const char *str, size_t len)
+{
+ zend_bool status;
+ char *strn = _compat_dup_str(str, len, 0);
+
+ status = zend_hash_exists(ht, strn, (uint)(len + 1));
+ efree(strn);
+ return status;
+}
+
+/*---------*/
+/* Changes from original version:
+ - Returns a zend_string
+ - If key is a string, returned zend_string must be released.
+*/
+static zend_always_inline int compat_zend_hash_get_current_key_ex(const HashTable *ht
+ , zend_string **str_index, zend_ulong *num_index, HashPosition *pos)
+{
+ int status;
+ char *str;
+ uint str_length;
+ ulong num;
+
+ status = zend_hash_get_current_key_ex(ht, &str, &str_length, &num, 0, pos);
+ if (status == HASH_KEY_IS_STRING) {
+ (*str_index) = zend_string_init(str, str_length - 1, ht->persistent);
+ } else if (status == HASH_KEY_IS_LONG) {
+ (*num_index) = (zend_ulong)num;
+ }
+ return status;
+}
+
+/*---------*/
+/* Diff with original :
+ - Type casts
+ - Return string length, without trailing null */
+
+static zend_always_inline int compat_zend_hash_str_get_current_key_ex(const HashTable *ht
+ , char **str_index, size_t *str_length, zend_ulong *num_index
+ , zend_bool duplicate, HashPosition *pos)
+{
+ int status;
+ uint length;
+ ulong num;
+
+ status = zend_hash_get_current_key_ex(ht, str_index, &length, &num, duplicate, pos);
+ if (status == HASH_KEY_IS_STRING) {
+ (*str_length) = (size_t)(length - 1);
+ } else if (status == HASH_KEY_IS_LONG) {
+ (*num_index) = (zend_ulong)num;
+ }
+ return status;
+}
+
+/*---------*/
+
+static zend_always_inline void *compat_zend_hash_get_current_data_ptr_ex(HashTable *ht
+ , HashPosition *pos)
+{
+ int status;
+ void **p;
+
+ status = zend_hash_get_current_data_ex(ht, (void **)(&p), pos);
+ return ((status == SUCCESS) ? (*p) : NULL);
+}
+
+#define compat_zend_hash_get_current_data_ptr(ht) \
+ compat_zend_hash_get_current_data_ptr_ex(ht, NULL)
+
+/*---------*/
+
+static zend_always_inline void *compat_zend_hash_get_current_data_ex(HashTable *ht
+ , HashPosition *pos)
+{
+ int status;
+ void **p;
+
+ status = zend_hash_get_current_data_ex(ht, (void **)(&p), pos);
+ return ((status == SUCCESS) ? p : NULL);
+}
+
+#define compat_zend_hash_get_current_data(ht) \
+ compat_zend_hash_get_current_data_ex(ht, NULL)
+
+#define compat_zend_hash_get_current_zval_ex(ht, pos) \
+ *((zval **)compat_zend_hash_get_current_data_ex(ht, pos))
+
+#define compat_zend_hash_get_current_zval(ht) \
+ compat_zend_hash_get_current_zval_ex(ht, NULL)
+
+/*------------------------------------------------------------*/
+
+#define ZEND_HASH_FOREACH(_ht, indirect) do { \
+ HashPosition _pos; \
+ for (zend_hash_internal_pointer_reset_ex(_ht, &_pos) \
+ ;;zend_hash_move_forward_ex(_ht, &_pos)) { \
+ if (zend_hash_has_more_elements_ex(_ht, &_pos) != SUCCESS) break;
+
+#define ZEND_HASH_FOREACH_END() \
+ } \
+} while (0)
+
+#define ZEND_HASH_FOREACH_PTR(_ht, _ptr) \
+ ZEND_HASH_FOREACH(_ht, 0); \
+ _ptr = compat_zend_hash_get_current_data_ptr_ex(_ht, &_pos);
+
+#define ZEND_HASH_FOREACH_NUM_KEY(_ht, _h) \
+ ZEND_HASH_FOREACH(_ht, 0); \
+ compat_zend_hash_get_current_key_ex(_ht, NULL, &_h, &_pos);
+
+#define ZEND_HASH_FOREACH_NUM_KEY_PTR(_ht, _h, _ptr) \
+ ZEND_HASH_FOREACH(_ht, 0); \
+ _ptr = compat_zend_hash_get_current_data_ptr_ex(_ht, &_pos); \
+ compat_zend_hash_get_current_key_ex(_ht, NULL, &_h, &_pos);
+
+/*============================================================================*/
+#endif /* PHP_7 */
+#endif /* _COMPAT_ZEND_HASH_H */
diff --git a/php_ketama/pecl-compat/src/zend_resource.h b/php_ketama/pecl-compat/src/zend_resource.h
new file mode 100644
index 0000000..65a0e1d
--- /dev/null
+++ b/php_ketama/pecl-compat/src/zend_resource.h
@@ -0,0 +1,152 @@
+/*
+ +----------------------------------------------------------------------+
+ | Compatibility macros for different PHP versions |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2016 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Adam Harvey |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef _COMPAT_ZEND_RESOURCE_H
+#define _COMPAT_ZEND_RESOURCE_H
+
+/*
+ * The PHP 5 and PHP 7 resource APIs use the same function names for mutually
+ * incompatible functions, which is unfortunate. A simple version of the PHP 5
+ * macro API can be implemented on top of the PHP 7 API, but not vice versa
+ * (since, for example, zend_register_resource() in PHP 5 also sets the zval,
+ * which is a separate action in PHP 7).
+ *
+ * Instead of using preprocessor trickery to try to mangle things into a sane
+ * API, I've implemented a minimal API that supports basic resource handling
+ * and delegates appropriately on both versions.
+ *
+ * Destructors should be registered using the normal
+ * zend_register_list_destructors() or zend_register_list_destructors_ex()
+ * functions. The destructor function should take a "zend_resource *" (there is
+ * an appropriate typedef in the PHP 5 section to make this work); as only a
+ * subset of fields are available across PHP versions, this should be treated
+ * as this struct in effect:
+ *
+ * typedef struct {
+ * void *ptr;
+ * int type;
+ * } zend_resource;
+ *
+ * Accessing other fields will likely result in compilation errors and/or
+ * segfaults.
+ */
+
+#include "zend_list.h"
+
+/**
+ * Deletes the resource.
+ *
+ * On PHP 5, this is equivalent to zend_list_delete(Z_LVAL_P(zv)).
+ * On PHP 7, this is equivalent to zend_list_close(Z_RES_P(zv)).
+ *
+ * @param zv The IS_RESOURCE zval to delete.
+ */
+static zend_always_inline void compat_zend_delete_resource(const zval *zv TSRMLS_DC);
+
+/**
+ * Fetches the resource.
+ *
+ * This API does not support the default ID that's possible with the PHP 5
+ * zend_fetch_resource() API, and will always set that value to -1.
+ *
+ * @param zv The IS_RESOURCE zval to fetch.
+ * @param rsrc_type_name The type name to use in error messages.
+ * @param rsrc_type The resource type ID.
+ * @return A void pointer to the resource, which needs to be typecast, or NULL
+ * on error.
+ */
+static zend_always_inline void *compat_zend_fetch_resource(zval *zv, const char *rsrc_type_name, int rsrc_type TSRMLS_DC);
+
+/**
+ * Registers a new resource.
+ *
+ * @param zv The zval to set to IS_RESOURCE with the new resource value.
+ * @param ptr A void pointer to the resource.
+ * @param rsrc_type The resource type ID.
+ */
+static zend_always_inline void compat_zend_register_resource(zval *zv, void *ptr, int rsrc_type TSRMLS_DC);
+
+#ifdef PHP_7
+/*============================================================================*/
+
+static zend_always_inline void compat_zend_delete_resource(const zval *zv TSRMLS_DC)
+{
+ if (IS_RESOURCE != Z_TYPE_P(zv)) {
+ return;
+ }
+
+ zend_list_close(Z_RES_P(zv));
+}
+
+/*---------*/
+
+static zend_always_inline void *compat_zend_fetch_resource(zval *zv, const char *rsrc_type_name, int rsrc_type TSRMLS_DC)
+{
+ if (IS_RESOURCE != Z_TYPE_P(zv)) {
+ return NULL;
+ }
+
+ return zend_fetch_resource(Z_RES_P(zv), rsrc_type_name, rsrc_type);
+}
+
+/*---------*/
+
+static zend_always_inline void compat_zend_register_resource(zval *zv, void *ptr, int rsrc_type TSRMLS_DC)
+{
+ ZVAL_RES(zv, zend_register_resource(ptr, rsrc_type));
+}
+
+#else
+/*== PHP 5 ===================================================================*/
+
+/* Used for destructors. */
+typedef zend_rsrc_list_entry zend_resource;
+
+/*---------*/
+
+static zend_always_inline void compat_zend_delete_resource(const zval *zv TSRMLS_DC)
+{
+ if (IS_RESOURCE != Z_TYPE_P(zv)) {
+ return;
+ }
+
+ zend_list_delete(Z_LVAL_P(zv));
+}
+
+/*---------*/
+
+static zend_always_inline void *compat_zend_fetch_resource(zval *zv, const char *rsrc_type_name, int rsrc_type TSRMLS_DC)
+{
+#if ZEND_MODULE_API_NO >= 20100412
+ return zend_fetch_resource(&zv TSRMLS_CC, -1, rsrc_type_name, NULL, 1, rsrc_type);
+#else
+ return zend_fetch_resource(&zv TSRMLS_CC, -1, (char *)rsrc_type_name, NULL, 1, rsrc_type);
+#endif
+}
+
+/*---------*/
+
+static zend_always_inline void compat_zend_register_resource(zval *zv, void *ptr, int rsrc_type TSRMLS_DC)
+{
+ ZEND_REGISTER_RESOURCE(zv, ptr, rsrc_type);
+}
+
+#endif /* PHP_7 */
+/*============================================================================*/
+
+#endif /* _COMPAT_ZEND_RESOURCE_H */
diff --git a/php_ketama/pecl-compat/src/zend_string.h b/php_ketama/pecl-compat/src/zend_string.h
new file mode 100644
index 0000000..2fb6280
--- /dev/null
+++ b/php_ketama/pecl-compat/src/zend_string.h
@@ -0,0 +1,283 @@
+/*
+ +----------------------------------------------------------------------+
+ | zend_string compatibility layer for PHP 5 & 7 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2005-2007 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Francois Laupretre |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef _COMPAT_ZEND_STRING_H
+#define _COMPAT_ZEND_STRING_H
+
+#ifdef PHP_7
+/*============================================================================*/
+#include "zend_string.h"
+
+#ifndef ZSTR_IS_PERSISTENT
+# define ZSTR_IS_PERSISTENT(s) (GC_FLAGS(s) & IS_STR_PERSISTENT)
+#endif
+
+#else
+/*============================================================================*/
+/*---- zend_string for PHP 5 ----*/
+
+struct _zend_string {
+ int persistent;
+ int hash_is_set; /* needed because computed hash may be null */
+ zend_ulong h; /* hash value */
+ uint32_t refcount;
+ size_t len;
+ char val[1];
+};
+
+typedef struct _zend_string zend_string;
+
+/* Shortcuts */
+
+#define ZSTR_VAL(zstr) (zstr)->val
+#define ZSTR_LEN(zstr) (zstr)->len
+#define ZSTR_H(zstr) (zstr)->h
+#define ZSTR_HASH(zstr) zend_string_hash_val(zstr)
+
+#define _ZSTR_HEADER_SIZE XtOffsetOf(zend_string, val)
+#define _ZSTR_STRUCT_SIZE(len) (_ZSTR_HEADER_SIZE + len + 1)
+
+#define ZSTR_IS_PERSISTENT(s) (s->persistent)
+
+/*---------*/
+
+static zend_always_inline uint32_t zend_string_refcount(zend_string *s)
+{
+ return (s->refcount);
+}
+
+/*---------*/
+
+static zend_always_inline uint32_t zend_string_addref(zend_string *s)
+{
+ return ++(s->refcount);
+}
+
+/*---------*/
+
+static zend_always_inline uint32_t zend_string_delref(zend_string *s)
+{
+ return --(s->refcount);
+}
+
+/*---------*/
+
+static zend_always_inline zend_ulong zend_string_hash_val(zend_string *s)
+{
+ char c, *p;
+
+ if (! s->hash_is_set) {
+ /* Compute with terminating null but preserve string */
+ p = &(ZSTR_VAL(s)[ZSTR_LEN(s)]);
+ c = (*p);
+ (*p) = '\0';
+ ZSTR_H(s) = zend_get_hash_value(ZSTR_VAL(s), ZSTR_LEN(s)+1);
+ (*p) = c;
+ s->hash_is_set = 1;
+ }
+ return ZSTR_H(s);
+}
+
+/*---------*/
+
+static zend_always_inline void zend_string_forget_hash_val(zend_string *s)
+{
+ s->hash_is_set = 0;
+ ZSTR_H(s) = 0; /* Security */
+}
+
+/*---------*/
+
+static zend_always_inline zend_string *zend_string_alloc(size_t len, int persistent)
+{
+ zend_string *ret = (zend_string *)pemalloc(ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
+ ret->persistent = persistent;
+ zend_string_forget_hash_val(ret);
+ ret->refcount = 1;
+ ZSTR_LEN(ret) = len;
+ return ret;
+}
+
+/*---------*/
+
+static zend_always_inline zend_string *zend_string_safe_alloc(size_t n
+ , size_t m, size_t l, int persistent)
+{
+ zend_string *ret = (zend_string *)safe_pemalloc(n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent);
+ ret->persistent = persistent;
+ zend_string_forget_hash_val(ret);
+ ret->refcount = 1;
+ ZSTR_LEN(ret) = l;
+ return ret;
+}
+
+/*---------*/
+
+static zend_always_inline zend_string *zend_string_init(const char *str, size_t len, int persistent)
+{
+ zend_string *ret = zend_string_alloc(len, persistent);
+
+ memcpy(ZSTR_VAL(ret), str, len);
+ ZSTR_VAL(ret)[len] = '\0';
+ return ret;
+}
+
+/*---------*/
+
+static zend_always_inline zend_string *zend_string_dup(zend_string *s, int persistent)
+{
+ zend_string *target;
+
+ target = zend_string_init(ZSTR_VAL(s), ZSTR_LEN(s), persistent);
+ if (s->hash_is_set) {
+ ZSTR_H(target) = ZSTR_H(s);
+ target->hash_is_set = 1;
+ }
+
+ return target;
+}
+
+/*---------*/
+
+static zend_always_inline zend_string *zend_string_realloc(zend_string *s
+ , size_t len, int persistent)
+{
+ zend_string *ret;
+
+ if (EXPECTED(s->refcount == 1)) {
+ ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
+ ZSTR_LEN(ret) = len;
+ zend_string_forget_hash_val(ret);
+ return ret;
+ }
+
+ zend_string_delref(s);
+ ret = zend_string_alloc(len, persistent);
+ memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN(len, ZSTR_LEN(s)) + 1);
+
+ return ret;
+}
+
+/*---------*/
+
+static zend_always_inline zend_string *zend_string_extend(zend_string *s
+ , size_t len, int persistent)
+{
+ zend_string *ret;
+
+ ZEND_ASSERT(len >= ZSTR_LEN(s));
+
+ if (EXPECTED(s->refcount == 1)) {
+ ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
+ ZSTR_LEN(ret) = len;
+ zend_string_forget_hash_val(ret);
+ return ret;
+ }
+
+ zend_string_delref(s);
+ ret = zend_string_alloc(len, persistent);
+ memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), ZSTR_LEN(s) + 1);
+
+ return ret;
+}
+
+/*---------*/
+
+static zend_always_inline zend_string *zend_string_truncate(zend_string *s
+ , size_t len, int persistent)
+{
+ zend_string *ret;
+
+ ZEND_ASSERT(len <= ZSTR_LEN(s));
+
+ if (EXPECTED(s->refcount == 1)) {
+ ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
+ ZSTR_LEN(ret) = len;
+ zend_string_forget_hash_val(ret);
+ return ret;
+ }
+
+ zend_string_delref(s);
+ ret = zend_string_alloc(len, persistent);
+ memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), len + 1);
+
+ return ret;
+}
+
+/*---------*/
+
+static zend_always_inline zend_string *zend_string_safe_realloc(zend_string *s
+ , size_t n, size_t m, size_t l, int persistent)
+{
+ zend_string *ret;
+
+ if (EXPECTED(s->refcount == 1)) {
+ ret = (zend_string *)safe_perealloc(s, n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent);
+ ZSTR_LEN(ret) = (n * m) + l;
+ zend_string_forget_hash_val(ret);
+ return ret;
+ }
+
+ zend_string_delref(s);
+ ret = zend_string_safe_alloc(n, m, l, persistent);
+ memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN((n * m) + l, ZSTR_LEN(s)) + 1);
+ return ret;
+}
+
+/*---------*/
+
+static zend_always_inline void zend_string_free(zend_string *s)
+{
+ if (s) {
+ pefree(s, s->persistent);
+ }
+}
+
+
+/*---------*/
+
+static zend_always_inline void zend_string_release(zend_string *s)
+{
+ if (s) {
+ s->refcount--;
+ if (s->refcount == 0) {
+ zend_string_free(s);
+ }
+ }
+}
+
+/*---------*/
+
+static zend_always_inline zend_string *zend_string_copy(zend_string *s)
+{
+ zend_string_addref(s);
+ return (s);
+}
+
+/*---------*/
+
+static zend_always_inline zend_bool zend_string_equals(zend_string *s1, zend_string *s2)
+{
+ return s1 == s2 || (s1->len == s2->len && !memcmp(s1->val, s2->val, s1->len));
+}
+
+#define zend_string_equals_literal(str, literal) \
+ ((str)->len == sizeof(literal)-1 && !memcmp((str)->val, literal, sizeof(literal) - 1))
+
+#endif /* PHP_7 */
+#endif /* _COMPAT_ZEND_STRING_H */