/****************************************************************************** * TinTin++ * * Copyright (C) 2004 (See CREDITS file) * * * * This program is protected under the GNU GPL (See COPYING) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ******************************************************************************/ /****************************************************************************** * (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t * * * * coded by Igor van den Hoven 2004 * ******************************************************************************/ #include "tintin.h" struct str_hash_index_data str_hash_index[MAX_STR_HASH]; unsigned short str_hash_len; /* Performs as well as Jenkin's one-at-a-time hash.- Igor */ unsigned short generate_hash_key(char *str) { unsigned int h; for (h = str_hash_len = 0 ; *str != 0 ; str++, str_hash_len++) { h -= (4 - (h >> 7)) * *str; } h += str_hash_len; return h % MAX_STR_HASH; } char *str_hash(char *str, int lines) { unsigned short hash; struct str_hash_data *hash_ptr; hash = generate_hash_key(str); for (hash_ptr = str_hash_index[hash].f_node ; hash_ptr ; hash_ptr = hash_ptr->next) { if (!strcmp(str, (char *) hash_ptr + gtd->str_hash_size)) { hash_ptr->count++; return (char *) hash_ptr + gtd->str_hash_size; } } hash_ptr = (struct str_hash_data *) calloc(1, str_hash_len + 1 + gtd->str_hash_size); hash_ptr->count = 1; hash_ptr->lines = lines; hash_ptr->hash = hash; strcpy((char *) hash_ptr + gtd->str_hash_size, str); LINK(hash_ptr, str_hash_index[hash].f_node, str_hash_index[hash].l_node); return (char *) hash_ptr + gtd->str_hash_size; } char *str_unhash(char *str) { struct str_hash_data *hash_ptr; hash_ptr = (struct str_hash_data *) (str - gtd->str_hash_size); if (--hash_ptr->count == 0) { UNLINK(hash_ptr, str_hash_index[hash_ptr->hash].f_node, str_hash_index[hash_ptr->hash].l_node); free(hash_ptr); } return NULL; } unsigned short str_hash_lines(char *str) { return ((struct str_hash_data *) (str - gtd->str_hash_size))->lines; } unsigned short str_hash_grep(char *str, int write) { struct str_hash_data *hash_ptr; hash_ptr = ((struct str_hash_data *) (str - gtd->str_hash_size)); if (write) { SET_BIT(hash_ptr->flags, STR_HASH_FLAG_NOGREP); } return HAS_BIT(hash_ptr->flags, STR_HASH_FLAG_NOGREP); } void reset_hash_table(void) { char temp[STRING_SIZE]; struct str_hash_data *hash_ptr; int hash; push_call("reset_hash_table()"); for (hash = 0 ; hash < MAX_STR_HASH ; hash++) { for (hash_ptr = str_hash_index[hash].f_node ; hash_ptr ; hash_ptr = hash_ptr->next) { hash_ptr->lines = word_wrap(gtd->ses, (char *) hash_ptr + gtd->str_hash_size, temp, FALSE); } } pop_call(); return; } DO_BUFFER(buffer_info) { struct str_hash_data *hash_ptr; int hash, hash_cnt, hash_max, index_cnt, string_cnt, pointer_cnt, hashed_size, unhashed_size; hash = hash_cnt = hash_max = index_cnt = string_cnt = pointer_cnt = hashed_size = unhashed_size = 0; for (hash = 0 ; hash < MAX_STR_HASH ; hash++) { if (str_hash_index[hash].f_node) { index_cnt++; } for (hash_cnt = 0, hash_ptr = str_hash_index[hash].f_node ; hash_ptr ; hash_ptr = hash_ptr->next) { if (hash != generate_hash_key((char *) hash_ptr + gtd->str_hash_size)) { tintin_printf2(ses, "corrupted hash node: %s", (char *) hash_ptr + gtd->str_hash_size); } hash_cnt += 1; string_cnt += 1; pointer_cnt += hash_ptr->count; hashed_size += gtd->str_hash_size + strlen((char *) hash_ptr + gtd->str_hash_size); unhashed_size += hash_ptr->count * strlen((char *) hash_ptr + gtd->str_hash_size); } if (hash_cnt > hash_max) { hash_max = hash_cnt; } } tintin_printf2(ses, "Total string count: %8d", string_cnt); tintin_printf2(ses, "Total pointer count: %8d", pointer_cnt); tintin_printf2(ses, "Total buckets count: %8d", index_cnt); tintin_printf2(ses, "Fullest bucket count: %8d", hash_max); tintin_printf2(ses, "Average bucket usage: %8.2f", (float) string_cnt / index_cnt); tintin_printf2(ses, "Total memory usage: %8d", hashed_size + MAX_STR_HASH * sizeof(struct str_hash_index_data)); tintin_printf2(ses, "Total memory saved: %8d", unhashed_size - hashed_size - MAX_STR_HASH * sizeof(struct str_hash_index_data)); }