antonio's blog

antonio's blog


Блог о всяком разном, связанном с разработкой ПО. Пишу редко, когда есть время и желание.

antonio
Author

Share


Tags


Разработка расширений для PHP. Хэш-таблицы (HashTables). Часть 2

antonioantonio

В данной части будет рассмотрено копирование и объединение хэш-таблиц. Перед тем как приступить к рассмотрению данного вопроса посмотрим на вспомогательную структуру zend_hash_key, объявленую в файле Zend/zend_hash.h:

typedef struct _zend_hash_key {  
    char *arKey;     /* Ключ для ассоциативного массива */
    uint nKeyLength; /* Размер в байтах ключа arKey */
    ulong h;    /* Числовой ключ нумерованного массива или рассчитанный хэш ключа arKey*/
} zend_hash_key;

Структура состоит из трех элементов по которым можно однозначно определить(идентифицировать) элемент в хэш-таблице.Указатель на структуру zend_hash_key передается во многие callback-функции, передаваемые в функции семейства zend_hash_*(), и используется в основном для идентификации элемента в хэш-таблице или его типа

void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size) - функция копирует каждый элемент из sorce в target используя callback-функцию pCopyConstructor. Если элемент, копируемый из src, уже есть в target, то он будет перезаписан

Параметры:

Прототип callback-функции pCopyConstructor:

void (*copy_ctor_func_t)(void *pElement)  

pElement - указатель на копируемый элемент

Пример:

/* Копируем активную таблицу символов в хэш-таблицу mht  */
HashTable *mht = NULL;  
HashTable *ast = NULL;

/* Выделяем память под хэш-таблицу и инициализируем ее */
ALLOC_HASHTABLE(mht);  
zend_hash_init(mht, 64, NULL, NULL, 1);

/* Получаем указатель на активную таблицу символов */
ast = EG(active_symbol_table);

/* Копируем каждый элемент из хэш-таблице ast в хэш-таблицу mht
 * В качестве callback-функции используем функцию zval_add_ref(). Функция
 * увеличивает счетчик ссылок
 */
zend_hash_copy(mht, ast, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));  

Объединение хэш-таблиц

void zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size, int overwrite) - функция копирует каждый элемент из sorce в target используя callback функцию pCopyConstructor. Если элемент, копируемый из src, уже есть в target и флаг overwrite не 0, то он будет перезаписан

Параметры:

Прототип callback функции pCopyConstructor:

typedef void (*copy_ctor_func_t)(void *pElement)  

pElement - указатель на копируемый элемент

void zend_hash_merge_ex(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, uint size, merge_checker_func_t pMergeSource, void *pParam) - функция выборочно копирует элементы из source в target используя callback-функцию pCopyConstructor. Для определения какой из элементов должен быть скоприрован используется callback-функция pMergeSource

Параметры:

Прототип callback-функции pCopyConstructor:

typedef void (*copy_ctor_func_t)(void *pElement)  

pElement - указатель на копируемый элемент

Прототип callback-функции pMergeSource:

typedef zend_bool (*merge_checker_func_t)(HashTable *target_ht, void *source_data, zend_hash_key *hash_key, void *pParam)  

target_ht - указатель на хэш-таблицу назначения, source_data - указатель на копируемые данные, hash_key - данные для идентификации элемента (См. zend_hash_key), pParam - произвольные данные

Пример копирования только ассоциативных элементов:

/* Callback-функция определения ассоциативного элемента */
static zend_bool is_associative(HashTable *ht, void *pData, zend_hash_key *hash_key, void *pParam) {  
    if( hash_key->arKey != NULL && hash_key->nKeyLength > 0 ) {
            return  1;
    }
    return 0;
}

void merge_if_associative() {  
    HashTable *mht = NULL;
    HashTable *ast = NULL;

    /* Выделяем память под хэш-таблицу и инициализируем ее */
    ALLOC_HASHTABLE(mht);
    zend_hash_init(mht, 64, NULL, NULL, 1);

    /* Получаем указатель на активную таблицу символов */
    ast = EG(active_symbol_table);

    /* Копируем */
    zend_hash_merge_ex(mht, ast, (copy_ctor_func_t)zval_add_ref, sizeof(zval*), (merge_checker_func_t)is_associative, NULL);
}

Пример копирования элементов не существующих в хэш-таблице назначения:

/* Callback-функция проверки существования элемента */
static zend_bool is_exists(HashTable *ht, void *pData, zend_hash_key *hash_key, void *pParam) {  
    if(zend_hash_quick_exists(ht, hash_key->arKey, hash_key->nKeyLength, hash_key->h) == 1 ) {
            return  0;
    }
    return 1;
}

void merge_if_not_exists() {  
    HashTable *mht = NULL;
    HashTable *ast = NULL;

    /* Выделяем память под хэш-таблицу и инициализируем ее */
    ALLOC_HASHTABLE(mht);
    zend_hash_init(mht, 64, NULL, NULL, 1);

    /* Получаем указатель на активную таблицу символов */
    ast = EG(active_symbol_table);

    /* Копируем */
    zend_hash_merge_ex(mht, ast, (copy_ctor_func_t)zval_add_ref, sizeof(zval*), (merge_checker_func_t)is_exists, NULL);
}
antonio
Author

antonio

Comments