Здравствуйте, _Lestat_, Вы писали:
Сперва дисклаймер.
Я никогда практически не использовал GLib. Так что прошу считать следующий код эскизом, а не готовым рецептом.
_L_>Хэш-таблице нужен ключ. У меня в одном файле может быть много вызовов функций и вызов в одной и той же строке может происходить в разных файлах. Т.о. уникальность региона дает пара (файл, строка в файле). Т.к. стандартные функции вычисления хэша работают с простыми типами, то мне придется писать свою хэш-функцию?
Хэш от строки — зачастую тупо сумма символов. Если коллизий слишком много, то можно взять CRC. Можно и MD5, но это уже паранойя.
Чтобы не мучаться с рукодельным управлением строками — используй
GString. Для него, кстати, и хэш-функция есть:
g_string_hash
_L_>Я не очень силен в этом. Объясните на пальцах, какие должны быть хэш-таблицы и что у них будет ключ, а что значение. По идее по кортежу (файл, строка, имя_фунции, и т.п....), должен возвращаться id региона. Как это провернуть? Через две хэш-таблицы?
Как я уже сказал, имён файлов немного, и для каждой записи повторять имя файла — это трата и памяти, и времени.
Поэтому отдельно заводишь таблицу (имя файла) -> (регистрационный номер файла).
static GHashTable* filenames;
static uint last_file_id;
static void delete_filename(gpointer p)
{
g_string_free((GString*)p, TRUE);
}
void init_filenames()
{
filenames = g_hash_table_new_full(g_string_hash, g_string_equal, delete_filename, NULL);
last_file_id = 0;
}
void destroy_filenames()
{
g_hash_table_destroy(filenames);
filenames = NULL;
last_file_id = 0;
}
uint file_id(g_string* name)
{
gpointer key, value; // key - это имя файла (GString*), value - счётчик (uint)
if(g_hash_table_lookup_extended(filenames, name, &key, &value))
return (uint)value;
else
g_hash_table_insert(filenames, g_string_new_len(name.str, name.len), (gpointer)(last_file_id++));
}
И отдельно — таблицу (номер файла, номер строки) -> (указатель на регион). Здесь, пожалуй, удобнее будет дерево — GTree.
struct RegionId { uint file, line; };
struct RegionInfo
{
RegionId id; // не должно меняться в течение всего времени существования объекта
// и дальше - всякая полезная информация
};
RegionInfo* new_region(........);
void delete_region(RegionInfo* p);
gint compare_region_ids(RegionId* x, RegionId* y, gpointer userdata)
{
if(x->file < y->file) return -1;
if(x->file > y->file) return +1;
if(x->line < y->line) return -1;
if(x->line > y->line) return +1;
return 0;
}
static GTree* regions;
void init_regions()
{
regions = g_tree_new_full(compare_region_ids, NULL, NULL, delete_region);
}
RegionInfo* lookup_region(uint file, uint line)
{
RegionId id = { file, line };
return g_tree_lookup(regions, &id);
}
void add_region(RegionInfo* region) // не копирует, а захватывает этот объект
{
g_tree_insert(regions, region->id, region);
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>