Subscribed unsubscribe Subscribe Subscribe

動的な配列サイズの増やし方 - PHPの場合

php

もう誰か触れてそうなもんだけど。

PHP : 2 倍?(これは PHP から使う配列の実装とは別物かな…?)

// Zend/zend_dynamic_array.c : 43行目〜
  if (da->current == da->allocated) {
    da->allocated *= 2;
http://www.kmonos.net/wlog/111.html?_2334100705

PHP の場合、動的に配列サイズが変更される箇所は、

の2つだけど *1、後者はハッシュテーブルなので、例の議論は当てはまらない。なので前者だけを見る。

上の zend_dynamic_array.c は関係ありません><

zend_operators.c:

ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
{
	zval op1_copy, op2_copy;
	int use_copy1 = 0, use_copy2 = 0;

	if (Z_TYPE_P(op1) != IS_STRING) {
		zend_make_printable_zval(op1, &op1_copy, &use_copy1);
	}
	if (Z_TYPE_P(op2) != IS_STRING) {
		zend_make_printable_zval(op2, &op2_copy, &use_copy2);
	}

	if (use_copy1) {
		/* We have created a converted copy of op1. Therefore, op1 won't become the result so
		 * we have to free it.
		 */
		if (result == op1) {
			zval_dtor(op1);
		}
		op1 = &op1_copy;
	}
	if (use_copy2) {
		op2 = &op2_copy;
	}
	if (result==op1) {	/* special case, perform operations on result */
		uint res_len = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);

		if (Z_STRLEN_P(result) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) {
			efree(Z_STRVAL_P(result));
			ZVAL_EMPTY_STRING(result);
			zend_error(E_ERROR, "String size overflow");
		}

		Z_STRVAL_P(result) = erealloc(Z_STRVAL_P(result), res_len+1);

		memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(result), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
		Z_STRVAL_P(result)[res_len]=0;
		Z_STRLEN_P(result) = res_len;
	} else {
		Z_STRLEN_P(result) = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
		Z_STRVAL_P(result) = (char *) emalloc(Z_STRLEN_P(result) + 1);
		memcpy(Z_STRVAL_P(result), Z_STRVAL_P(op1), Z_STRLEN_P(op1));
		memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
		Z_STRVAL_P(result)[Z_STRLEN_P(result)] = 0;
		Z_TYPE_P(result) = IS_STRING;
	}
	if (use_copy1) {
		zval_dtor(op1);
	}
	if (use_copy2) {
		zval_dtor(op2);
	}
	return SUCCESS;
}
/* }}} */

PHP で文字列を格納する構造体には、容量という概念がない。なので、文字列を同じ変数に対して連結していくときも、(連結元のサイズ) + (連結対象のサイズ) で realloc してるだけでした。

*1:拡張モジュールなどで独自に実装している場合はあるけど、ここではユーザが直に触れられるものだけを扱う