GLib: Hashtable не находит значения правильно

Итак, недавно я использовал типы GLib, такие как списки и карты, но столкнулся с довольно неприятной проблемой.

Начав, я создал свою хеш-таблицу как таковую:

BoneIdMap = g_hash_table_new(g_direct_hash, g_str_equal);

Затем я пробую это, вставляю uint в строковый ключ, и он отлично работает:

char* string = alloq_calloc(&model->dynamic, strlen(aimesh->mBones[x]->mName.data) + 1, sizeof(char));
strcpy(string, aimesh->mBones[x]->mName.
if(map_find(&model->BoneIdMap, string, &handle)) {
    index = *handle;
} else {
    index = model->BoneIdMap.size;
}
map_insert(&model->BoneIdMap, &index, sizeof(uint), string);

Обратите внимание: я динамически выделяю указатель, потому что я пытался просто передать статический массив, и это не работает (оказывается, оба не работают)

Затем я продолжаю пытаться получить эти uints позже:

char* string = alloq_calloc(&model->dynamic, strlen(ainode->mName.data) + 1, sizeof(char));
strcpy(string, ainode->mName.data);
/* Time to do some debugging */
if(map_find(&model->BoneIdMap, string, &handle)) {

Но это просто не работает... Я попытался получить все ключи в массив:

uint len;
char** arr = g_hash_table_get_keys_as_array(model->BoneIdMap.table, &len);
for(int i = 0; i < len; ++i) {
   if(arr[i]) printf("Key: %s\n", arr[i]);
       if(!strcmp(arr[i], ainode->mName.data)) printf("Yes!\n");
}
printf("----------------------------\n");

И это работает!!! (???)

Key: pelvis
Key: toe.L
Yes!
Key: sheath
Key: lamp
----------------------------
Key: toe.R
Key: shin.L
Key: fingerstip.R
Key: neck
Key: thigh.R
Key: fingers.L
Key: shin.R
Key: spine
Key: lamp
Key: head
Key: fingerstip.L
Key: thm_end.L
Key: thm_end.R
Key: tiptoe.L
Yes!
Key: upperarm.R

Обратите внимание, что если бы я добавил ключ с помощью статической строки прямо здесь, помимо функции печати выше, и попытался бы найти его, это сработало бы! Что приводит меня в некоторое замешательство...

Между прочим, mName — это aiString (ASSIMP) —

Public Attributes
char    data [MAXLEN]
    String buffer.
size_t  length
    Binary length of the string excluding the terminal 0.

Спасибо за чтение...


person Whiteclaws    schedule 29.06.2017    source источник
comment
Пожалуйста, поделитесь своим кодом map_insert и map_find, поскольку я предполагаю, что обе они являются функциями-оболочками вокруг функций хэш-таблицы GLib.   -  person tgregory    schedule 29.06.2017


Ответы (1)


Вы используете хэш-функцию g_direct_hash, которая предназначена для gpointer для строковых ключей, попробуйте изменить ее на g_str_hash.

// g_direct_hash implementation seems to be this
guint
g_direct_hash (gconstpointer v)
{
  return GPOINTER_TO_UINT (v);
}

Что касается того, почему он работает со статическим строковым литералом, я бы сказал, что компилятор оптимизирует двоичное пространство и сворачивает два литерала с одинаковым содержимым в одну запись сегмента DATA, поэтому он хэширует один и тот же указатель, поэтому он выглядит так, как будто он работает правильно, хотя он не.

person tgregory    schedule 29.06.2017
comment
Но я не хэширую строки, я пытаюсь сопоставить uints со строками. По сути, строки в качестве ключей и uints в качестве значений. - person Whiteclaws; 29.06.2017
comment
Хэш-таблица @Whiteclaws (как и общая структура данных) работает следующим образом. На положенном ключе хеширования в большинстве случаев хеш представляет собой целочисленное значение в некотором диапазоне, и этот диапазон чаще всего является количеством сегментов хеш-таблицы. Поэтому, когда происходит поиск ключа, сначала вычисляется хэш искомого ключа, после чего нам нужно найти корзину и сравнить сохраненный ключ с ключом поиска (поскольку существует более одного ключа, производящего один и тот же хеш). Вот почему конструктор хеш-таблицы имеет функции хеширования и сравнения. И именно поэтому им обоим нужно знать, как работать со строкой, оканчивающейся нулем. - person tgregory; 29.06.2017