📄 array.c
字号:
}}/* }}} *//* {{{ proto array range(mixed low, mixed high) Create an array containing the range of integers or characters from low to high (inclusive) */PHP_FUNCTION(range){ zval **zlow, **zhigh; if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &zlow, &zhigh) == FAILURE) { WRONG_PARAM_COUNT; } /* allocate an array for return */ array_init(return_value); if (Z_TYPE_PP(zlow) == IS_STRING && Z_TYPE_PP(zhigh) == IS_STRING && Z_STRLEN_PP(zlow) == 1 && Z_STRLEN_PP(zhigh) == 1) { unsigned char low, high; low = *((unsigned char *)Z_STRVAL_PP(zlow)); high = *((unsigned char *)Z_STRVAL_PP(zhigh)); if (low>high) { for (; low >= high; (low)--) { add_next_index_stringl(return_value, (char *)&low, 1, 1); if ((int)low == 0) { break; } } } else { for (; low <= high; (low)++) { add_next_index_stringl(return_value, (char *)&low, 1, 1); if ((int)low == 255) { break; } } } } else { int low, high; convert_to_long_ex(zlow); convert_to_long_ex(zhigh); low = Z_LVAL_PP(zlow); high = Z_LVAL_PP(zhigh); if (low > high) { for (; low >= high; low--) { add_next_index_long(return_value, low); } } else { for (; low <= high; low++) { add_next_index_long(return_value, low); } } }}/* }}} */static void array_data_shuffle(zval *array TSRMLS_DC){ Bucket **elems, *temp; HashTable *hash; int j, n_elems, rnd_idx, n_left; n_elems = zend_hash_num_elements(Z_ARRVAL_P(array)); if (n_elems < 1) { return; } elems = (Bucket **)safe_emalloc(sizeof(Bucket *), n_elems, 0); hash = Z_ARRVAL_P(array); n_left = n_elems; for (j = 0, temp = hash->pListHead; temp; temp = temp->pListNext) elems[j++] = temp; while (--n_left) { rnd_idx = php_rand(TSRMLS_C); RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX); if (rnd_idx != n_left) { temp = elems[n_left]; elems[n_left] = elems[rnd_idx]; elems[rnd_idx] = temp; } } HANDLE_BLOCK_INTERRUPTIONS(); hash->pListHead = elems[0]; hash->pListTail = NULL; hash->pInternalPointer = hash->pListHead; for (j = 0; j < n_elems; j++) { if (hash->pListTail) { hash->pListTail->pListNext = elems[j]; } elems[j]->pListLast = hash->pListTail; elems[j]->pListNext = NULL; hash->pListTail = elems[j]; } temp = hash->pListHead; j = 0; while (temp != NULL) { temp->nKeyLength = 0; temp->h = j++; temp = temp->pListNext; } hash->nNextFreeElement = n_elems; zend_hash_rehash(hash); HANDLE_UNBLOCK_INTERRUPTIONS(); efree(elems);}/* {{{ proto bool shuffle(array array_arg) Randomly shuffle the contents of an array */PHP_FUNCTION(shuffle){ zval *array; if (zend_parse_parameters(1 TSRMLS_CC, "a", &array) == FAILURE) { RETURN_FALSE; } array_data_shuffle(array TSRMLS_CC); RETURN_TRUE;}/* }}} *//* HashTable* php_splice(HashTable *in_hash, int offset, int length, zval ***list, int list_count, HashTable **removed) */HashTable* php_splice(HashTable *in_hash, int offset, int length, zval ***list, int list_count, HashTable **removed){ HashTable *out_hash = NULL; /* Output hashtable */ int num_in, /* Number of entries in the input hashtable */ pos, /* Current position in the hashtable */ i; /* Loop counter */ Bucket *p; /* Pointer to hash bucket */ zval *entry; /* Hash entry */ /* If input hash doesn't exist, we have nothing to do */ if (!in_hash) return NULL; /* Get number of entries in the input hash */ num_in = zend_hash_num_elements(in_hash); /* Clamp the offset.. */ if (offset > num_in) offset = num_in; else if (offset < 0 && (offset=num_in+offset) < 0) offset = 0; /* ..and the length */ if (length < 0) { length = num_in-offset+length; } else if (((unsigned) offset + (unsigned) length) > num_in) { length = num_in-offset; } /* Create and initialize output hash */ ALLOC_HASHTABLE(out_hash); zend_hash_init(out_hash, 0, NULL, ZVAL_PTR_DTOR, 0); /* Start at the beginning of the input hash and copy entries to output hash until offset is reached */ for (pos=0, p=in_hash->pListHead; pos<offset && p ; pos++, p=p->pListNext) { /* Get entry and increase reference count */ entry = *((zval **)p->pData); entry->refcount++; /* Update output hash depending on key type */ if (p->nKeyLength) zend_hash_update(out_hash, p->arKey, p->nKeyLength, &entry, sizeof(zval *), NULL); else zend_hash_next_index_insert(out_hash, &entry, sizeof(zval *), NULL); } /* If hash for removed entries exists, go until offset+length and copy the entries to it */ if (removed != NULL) { for ( ; pos<offset+length && p; pos++, p=p->pListNext) { entry = *((zval **)p->pData); entry->refcount++; if (p->nKeyLength) zend_hash_update(*removed, p->arKey, p->nKeyLength, &entry, sizeof(zval *), NULL); else zend_hash_next_index_insert(*removed, &entry, sizeof(zval *), NULL); } } else /* otherwise just skip those entries */ for ( ; pos<offset+length && p; pos++, p=p->pListNext); /* If there are entries to insert.. */ if (list != NULL) { /* ..for each one, create a new zval, copy entry into it and copy it into the output hash */ for (i=0; i<list_count; i++) { entry = *list[i]; if (entry->refcount>=1000) { zval *tmp = (zval *) emalloc(sizeof(zval)); *tmp = *entry; zval_copy_ctor(tmp); tmp->refcount = 1; tmp->is_ref = 0; entry = tmp; } else { entry->refcount++; } zend_hash_next_index_insert(out_hash, &entry, sizeof(zval *), NULL); } } /* Copy the remaining input hash entries to the output hash */ for ( ; p ; p=p->pListNext) { entry = *((zval **)p->pData); entry->refcount++; if (p->nKeyLength) zend_hash_update(out_hash, p->arKey, p->nKeyLength, &entry, sizeof(zval *), NULL); else zend_hash_next_index_insert(out_hash, &entry, sizeof(zval *), NULL); } zend_hash_internal_pointer_reset(out_hash); return out_hash;}/* }}} *//* {{{ proto int array_push(array stack, mixed var [, mixed ...]) Pushes elements onto the end of the array */PHP_FUNCTION(array_push){ zval ***args, /* Function arguments array */ *stack, /* Input array */ *new_var; /* Variable to be pushed */ int i, /* Loop counter */ argc; /* Number of function arguments */ /* Get the argument count and check it */ argc = ZEND_NUM_ARGS(); if (argc < 2) { WRONG_PARAM_COUNT; } /* Allocate arguments array and get the arguments, checking for errors. */ args = (zval ***)safe_emalloc(sizeof(zval **), argc, 0); if (zend_get_parameters_array_ex(argc, args) == FAILURE) { efree(args); WRONG_PARAM_COUNT; } /* Get first argument and check that it's an array */ stack = *args[0]; if (Z_TYPE_P(stack) != IS_ARRAY) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "First argument should be an array"); efree(args); RETURN_FALSE; } /* For each subsequent argument, make it a reference, increase refcount, and add it to the end of the array */ for (i=1; i<argc; i++) { new_var = *args[i]; new_var->refcount++; zend_hash_next_index_insert(Z_ARRVAL_P(stack), &new_var, sizeof(zval *), NULL); } /* Clean up and return the number of values in the stack */ efree(args); RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));}/* }}} *//* {{{ void _phpi_pop(INTERNAL_FUNCTION_PARAMETERS, int which_end) */static void _phpi_pop(INTERNAL_FUNCTION_PARAMETERS, int off_the_end){ zval **stack, /* Input stack */ **val; /* Value to be popped */ char *key = NULL; uint key_len = 0; ulong index; /* Get the arguments and do error-checking */ if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &stack) == FAILURE) { WRONG_PARAM_COUNT; } if (Z_TYPE_PP(stack) != IS_ARRAY) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array"); return; } if (zend_hash_num_elements(Z_ARRVAL_PP(stack)) == 0) { return; } /* Get the first or last value and copy it into the return value */ if (off_the_end) zend_hash_internal_pointer_end(Z_ARRVAL_PP(stack)); else zend_hash_internal_pointer_reset(Z_ARRVAL_PP(stack)); zend_hash_get_current_data(Z_ARRVAL_PP(stack), (void **)&val); *return_value = **val; zval_copy_ctor(return_value); INIT_PZVAL(return_value); /* Delete the first or last value */ zend_hash_get_current_key_ex(Z_ARRVAL_PP(stack), &key, &key_len, &index, 0, NULL); zend_hash_del_key_or_index(Z_ARRVAL_PP(stack), key, key_len, index, (key) ? HASH_DEL_KEY : HASH_DEL_INDEX); /* If we did a shift... re-index like it did before */ if (!off_the_end) { int k = 0; Bucket *p = Z_ARRVAL_PP(stack)->pListHead; while (p != NULL) { if (p->nKeyLength == 0) { p->h = k++; } p = p->pListNext; } Z_ARRVAL_PP(stack)->nNextFreeElement = k; zend_hash_rehash(Z_ARRVAL_PP(stack)); } else if (!key_len && index >= Z_ARRVAL_PP(stack)->nNextFreeElement-1) { Z_ARRVAL_PP(stack)->nNextFreeElement = Z_ARRVAL_PP(stack)->nNextFreeElement - 1; } zend_hash_internal_pointer_reset(Z_ARRVAL_PP(stack));}/* }}} *//* {{{ proto mixed array_pop(array stack) Pops an element off the end of the array */PHP_FUNCTION(array_pop){ _phpi_pop(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);}/* }}} *//* {{{ proto mixed array_shift(array stack) Pops an element off the beginning of the array */PHP_FUNCTION(array_shift){ _phpi_pop(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);}/* }}} *//* {{{ proto int array_unshift(array stack, mixed var [, mixed ...]) Pushes elements onto the beginning of the array */PHP_FUNCTION(array_unshift){ zval ***args, /* Function arguments array */ *stack; /* Input stack */ HashTable *new_hash; /* New hashtable for the stack */ int argc; /* Number of function arguments */ /* Get the argument count and check it */ argc = ZEND_NUM_ARGS(); if (argc < 2) { WRONG_PARAM_COUNT; } /* Allocate arguments array and get the arguments, checking for errors. */ args = (zval ***)safe_emalloc(sizeof(zval **), argc, 0); if (zend_get_parameters_array_ex(argc, args) == FAILURE) { efree(args); WRONG_PARAM_COUNT; } /* Get first argument and check that it's an array */ stack = *args[0]; if (Z_TYPE_P(stack) != IS_ARRAY) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "The first argument should be an array"); efree(args); RETURN_FALSE; } /* Use splice to insert the elements at the beginning. Destroy old hashtable and replace it with new one */ new_hash = php_splice(Z_ARRVAL_P(stack), 0, 0, &args[1], argc-1, NULL); zend_hash_destroy(Z_ARRVAL_P(stack)); *Z_ARRVAL_P(stack) = *new_hash; FREE_HASHTABLE(new_hash); /* Clean up and return the number of elements in the stack */ efree(args); RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));}/* }}} *//* {{{ proto array array_splice(array input, int offset [, int length [, array replacement]]) Removes the elements designated by offset and length and replace them with supplied array */PHP_FUNCTION(array_splice){ zval ***args, /* Function arguments array */ *array, /* Input array */ ***repl = NULL; /* Replacement elements */ HashTable *new_hash = NULL; /* Output array's hash */ Bucket *p; /* Bucket used for traversing hash */ int argc, /* Number of function arguments */ i, offset, length, repl_num = 0; /* Number of replacement elements */ /* Get the argument count and check it */ argc = ZEND_NUM_ARGS(); if (argc < 2 || argc > 4) { WRONG_PARAM_COUNT; } /* Allocate arguments array and get the arguments, checking for errors. */ args = (zval ***)safe_emalloc(sizeof(zval **), argc, 0); if (zend_get_parameters_array_ex(argc, args) == FAILURE) { efree(args); WRONG_PARAM_COUNT; } /* Get first argument and check that it's an array */ array = *args[0]; if (Z_TYPE_P(array) != IS_ARRAY) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "The first argument should be an array"); efree(args); return; } /* Get the next two arguments. If length is omitted, it's assumed to be until the end of the array */ convert_to_long_ex(args[1]); offset = Z_LVAL_PP(args[1]); if (argc > 2) { convert_to_long_ex(args[2]); length = Z_LVAL_PP(args[2]); } else length = zend_hash_num_elements(Z_ARRVAL_P(array)); if (argc == 4) { /* Make sure the last argument, if passed, is an array */ convert_to_array_ex(args[3]); /* Create the array of replacement elements */ repl_num = zend_hash_num_elements(Z_ARRVAL_PP(args[3])); repl = (zval ***)safe_emalloc(sizeof(zval **), repl_num, 0); for (p=Z_ARRVAL_PP(args[3])->pListHead, i=0; p; p=p->pListNext, i++) { repl[i] = ((zval **)p->pData); } } /* Initialize return value */ array_init(return_value); /* Perform splice */ new_hash = php_splice(Z_ARRVAL_P(array), offset, length, repl, repl_num, &Z_ARRVAL_P(return_value)); /* Replace input array's hashtable with the new one */ zend_hash_destroy(Z_ARRVAL_P(array)); *Z_ARRVAL_P(array) = *new_hash; FREE_HASHTABLE(new_hash); /* Clean up */ if (argc == 4) efree(repl); efree(args);}/* }}} *//* {{{ proto array array_slice(array input, int offset [, int length]) Returns elements specified by offset and length */PHP_FUNCTION(array_slice){ zval **input, /* Input array */ **offset, /* Offset to get elements from */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -