Reimplement Quickfill using hash tables -- big memory savings.

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@2874 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Dave Peticolas 2000-09-17 06:53:50 +00:00
parent 5a3c34b0ba
commit 34f79314a3
6 changed files with 168 additions and 119 deletions

View File

@ -32,9 +32,16 @@
#include "util.h"
struct _QuickFill
{
char * text; /* the first matching text string */
GHashTable *matches; /* array of children in the tree */
};
/** PROTOTYPES ******************************************************/
static void qfInsertTextRec(QuickFill *qf, const char * text, int depth,
QuickFillSort sort);
static void quickfill_insert_recursive (QuickFill *qf, const char *text,
int depth, QuickFillSort sort);
/* This static indicates the debugging module that this .o belongs to. */
static short module = MOD_REGISTER;
@ -42,53 +49,55 @@ static short module = MOD_REGISTER;
/********************************************************************\
\********************************************************************/
static int
CHAR_TO_INDEX(char c)
static guint
quickfill_hash (gconstpointer key)
{
int index = toupper(c);
return GPOINTER_TO_UINT (key);
}
if (index >= (QFNUM - 1))
return 0;
static gint
quickfill_compare (gconstpointer key1, gconstpointer key2)
{
guint k1 = GPOINTER_TO_UINT (key1);
guint k2 = GPOINTER_TO_UINT (key2);
return index + 1;
return (k1 == k2);
}
/********************************************************************\
\********************************************************************/
QuickFill *
xaccMallocQuickFill(void)
gnc_quickfill_new (void)
{
QuickFill *qf;
int i;
qf = g_new(QuickFill, 1);
for(i = 0; i < QFNUM; i++)
qf->qf[i] = NULL;
qf = g_new (QuickFill, 1);
qf->text = NULL;
qf->matches = g_hash_table_new (quickfill_hash, quickfill_compare);
return qf;
}
/********************************************************************\
\********************************************************************/
void
xaccFreeQuickFill(QuickFill *qf)
static void
destroy_helper (gpointer key, gpointer value, gpointer data)
{
int i;
gnc_quickfill_destroy (value);
}
if (qf == NULL )
void
gnc_quickfill_destroy (QuickFill *qf)
{
if (qf == NULL)
return;
for(i = 0; i < QFNUM; i++)
{
xaccFreeQuickFill(qf->qf[i]);
qf->qf[i] = NULL;
}
g_hash_table_foreach (qf->matches, destroy_helper, NULL);
g_hash_table_destroy (qf->matches);
qf->matches = NULL;
if (qf->text != NULL)
g_free(qf->text);
g_free(qf->text);
qf->text = NULL;
g_free(qf);
@ -96,21 +105,34 @@ xaccFreeQuickFill(QuickFill *qf)
/********************************************************************\
\********************************************************************/
QuickFill *
xaccGetQuickFill(QuickFill *qf, char c)
const char *
gnc_quickfill_string (QuickFill *qf)
{
if (qf == NULL)
return NULL;
DEBUG("xaccGetQuickFill(): index = %d\n",CHAR_TO_INDEX(c));
return qf->qf[CHAR_TO_INDEX(c)];
return qf->text;
}
/********************************************************************\
\********************************************************************/
QuickFill *
xaccGetQuickFillStrLen(QuickFill *qf, const char *str, int len)
gnc_quickfill_get_char_match (QuickFill *qf, char c)
{
guint key = toupper(c);
if (qf == NULL)
return NULL;
DEBUG ("xaccGetQuickFill(): index = %u\n", key);
return g_hash_table_lookup (qf->matches, GUINT_TO_POINTER (key));
}
/********************************************************************\
\********************************************************************/
QuickFill *
gnc_quickfill_get_string_len_match (QuickFill *qf, const char *str, int len)
{
if (str == NULL)
return NULL;
@ -120,7 +142,8 @@ xaccGetQuickFillStrLen(QuickFill *qf, const char *str, int len)
if (qf == NULL)
return NULL;
qf = qf->qf[CHAR_TO_INDEX(*str)];
qf = gnc_quickfill_get_char_match (qf, *str);
str++;
len--;
}
@ -131,67 +154,66 @@ xaccGetQuickFillStrLen(QuickFill *qf, const char *str, int len)
/********************************************************************\
\********************************************************************/
QuickFill *
xaccGetQuickFillStr(QuickFill *qf, const char *str)
gnc_quickfill_get_string_match (QuickFill *qf, const char *str)
{
if (str == NULL)
return NULL;
return xaccGetQuickFillStrLen(qf, str, strlen(str));
return gnc_quickfill_get_string_len_match (qf, str, strlen(str));
}
/********************************************************************\
\********************************************************************/
QuickFill *
xaccGetQuickFillUniqueLen( QuickFill *qf, int * length )
static void
unique_len_helper (gpointer key, gpointer value, gpointer data)
{
int last = 0;
int count;
int i;
QuickFill **qf_p = data;
*length = 0;
*qf_p = value;
}
QuickFill *
gnc_quickfill_get_unique_len_match (QuickFill *qf, int * length)
{
if (length != NULL)
*length = 0;
if (qf == NULL)
return NULL;
while (1)
{
count = 0;
for(i = 0; i < QFNUM; i++)
{
if (qf->qf[i] != NULL)
{
count++;
if (count > 1)
return qf;
guint count;
last = i;
}
}
count = g_hash_table_size (qf->matches);
if (count == 0)
if (count != 1)
return qf;
qf = qf->qf[last];
(*length)++;
g_hash_table_foreach (qf->matches, unique_len_helper, &qf);
if (length != NULL)
(*length)++;
}
}
/********************************************************************\
\********************************************************************/
void
xaccQFInsertText(QuickFill *qf, const char * text, QuickFillSort sort)
gnc_quickfill_insert (QuickFill *qf, const char * text, QuickFillSort sort)
{
qfInsertTextRec(qf, text, 0, sort);
quickfill_insert_recursive (qf, text, 0, sort);
}
/********************************************************************\
\********************************************************************/
static void
qfInsertTextRec( QuickFill *qf, const char *text, int depth,
QuickFillSort sort )
quickfill_insert_recursive (QuickFill *qf, const char *text, int depth,
QuickFillSort sort)
{
int index;
guint key;
char *old_text;
QuickFill *match_qf;
if (qf == NULL)
return;
@ -199,12 +221,16 @@ qfInsertTextRec( QuickFill *qf, const char *text, int depth,
if ((text == NULL) || (text[depth] == '\0'))
return;
index = CHAR_TO_INDEX(text[depth]);
key = toupper(text[depth]);
if( qf->qf[index] == NULL )
qf->qf[index] = xaccMallocQuickFill();
match_qf = g_hash_table_lookup (qf->matches, GUINT_TO_POINTER (key));
if (match_qf == NULL)
{
match_qf = gnc_quickfill_new ();
g_hash_table_insert (qf->matches, GUINT_TO_POINTER (key), match_qf);
}
old_text = qf->qf[index]->text;
old_text = match_qf->text;
switch(sort)
{
@ -217,7 +243,7 @@ qfInsertTextRec( QuickFill *qf, const char *text, int depth,
/* If there's no string there already, just put the new one in. */
if (old_text == NULL)
{
qf->qf[index]->text = g_strdup (text);
match_qf->text = g_strdup (text);
break;
}
@ -227,11 +253,11 @@ qfInsertTextRec( QuickFill *qf, const char *text, int depth,
break;
g_free (old_text);
qf->qf[index]->text = g_strdup (text);
match_qf->text = g_strdup (text);
break;
}
qfInsertTextRec(qf->qf[index], text, ++depth, sort);
quickfill_insert_recursive (match_qf, text, ++depth, sort);
}
/********************** END OF FILE *********************************\

View File

@ -28,6 +28,9 @@
#include "config.h"
#include <glib.h>
/** STRUCTS *********************************************************/
/* The way quickfill works is this: the decscription field of a transaction
@ -47,29 +50,29 @@
* when the end of the descriptions string is reached.
*/
#define QFNUM 257 /* 256 characters + 1 */
typedef enum
{
QUICKFILL_LIFO,
QUICKFILL_ALPHA
} QuickFillSort;
typedef struct _quickfill {
char * text; /* the first matching text string */
struct _quickfill *qf[QFNUM]; /* array of children in the tree */
} QuickFill;
typedef struct _QuickFill QuickFill;
/** PROTOTYPES ******************************************************/
QuickFill *xaccMallocQuickFill( void );
void xaccFreeQuickFill( QuickFill *qf );
QuickFill *xaccGetQuickFill( QuickFill *qf, char c );
QuickFill *xaccGetQuickFillStr( QuickFill *qf, const char *str );
QuickFill *xaccGetQuickFillStrLen( QuickFill *qf, const char *str, int len );
QuickFill *xaccGetQuickFillUniqueLen( QuickFill *qf, int *len );
void xaccQFInsertText( QuickFill *qf, const char *text, QuickFillSort );
QuickFill * gnc_quickfill_new (void);
void gnc_quickfill_destroy (QuickFill *qf);
const char * gnc_quickfill_string (QuickFill *qf);
QuickFill * gnc_quickfill_get_char_match (QuickFill *qf, char c);
QuickFill * gnc_quickfill_get_string_match (QuickFill *qf, const char *str);
QuickFill * gnc_quickfill_get_string_len_match (QuickFill *qf,
const char *str, int len);
QuickFill * gnc_quickfill_get_unique_len_match (QuickFill *qf, int *len);
void gnc_quickfill_insert (QuickFill *qf, const char *text,
QuickFillSort sort_code);
#endif /* __QUICKFILL_H__ */

View File

@ -126,7 +126,7 @@ void xaccInitComboCell (ComboCell *cell)
cell->cell.gui_private = box;
box->qf = xaccMallocQuickFill();
box->qf = gnc_quickfill_new ();
box->in_list_select = FALSE;
box->strict = TRUE;
@ -319,7 +319,7 @@ void xaccDestroyComboCell (ComboCell *cell)
g_list_free(box->menustrings);
box->menustrings = NULL;
xaccFreeQuickFill(box->qf);
gnc_quickfill_destroy (box->qf);
box->qf = NULL;
g_free(box->ignore_string);
@ -355,8 +355,8 @@ xaccClearComboCellMenu (ComboCell * cell)
g_list_free(box->menustrings);
box->menustrings = NULL;
xaccFreeQuickFill(box->qf);
box->qf = xaccMallocQuickFill();
gnc_quickfill_destroy (box->qf);
box->qf = gnc_quickfill_new ();
if (box->item_list != NULL)
{
@ -430,7 +430,7 @@ xaccAddComboCellMenuItem (ComboCell *cell, char * menustr)
else
box->list_in_sync = FALSE;
xaccQFInsertText(box->qf, menustr, QUICKFILL_ALPHA);
gnc_quickfill_insert (box->qf, menustr, QUICKFILL_ALPHA);
box->list_sorted = FALSE;
}
@ -456,6 +456,7 @@ ComboMV (BasicCell *_cell,
{
ComboCell *cell = (ComboCell *) _cell;
PopBox *box = cell->cell.gui_private;
const char *match_str;
const char *retval;
QuickFill *match;
gboolean pop_list;
@ -485,9 +486,11 @@ ComboMV (BasicCell *_cell,
return newval;
}
match = xaccGetQuickFillStr(box->qf, newval);
match = gnc_quickfill_get_string_match (box->qf, newval);
if ((match == NULL) || (match->text == NULL))
match_str = gnc_quickfill_string (match);
if ((match == NULL) || (match_str == NULL))
{
xaccSetBasicCellValue (_cell, newval);
@ -498,7 +501,7 @@ ComboMV (BasicCell *_cell,
return newval;
}
retval = g_strdup(match->text);
retval = g_strdup(match_str);
*start_selection = strlen(newval);
*end_selection = -1;
@ -541,6 +544,7 @@ ComboDirect (BasicCell *bcell,
gboolean keep_on_going = FALSE;
gboolean extra_colon;
QuickFill *match;
const char *match_str;
char *search;
int prefix_len;
int new_pos;
@ -568,20 +572,21 @@ ComboDirect (BasicCell *bcell,
!keep_on_going)
return FALSE;
match = xaccGetQuickFillStrLen(box->qf, oldval,
*cursor_position);
match = gnc_quickfill_get_string_len_match (box->qf, oldval, *cursor_position);
if (match == NULL)
return TRUE;
match = xaccGetQuickFillUniqueLen(match, &prefix_len);
match = gnc_quickfill_get_unique_len_match (match, &prefix_len);
if (match == NULL)
return TRUE;
if ((match->text != NULL) &&
(strncmp(match->text, oldval, length) == 0) &&
(strcmp(match->text, oldval) != 0))
match_str = gnc_quickfill_string (match);
if ((match_str != NULL) &&
(strncmp(match_str, oldval, length) == 0) &&
(strcmp(match_str, oldval) != 0))
{
*newval_ptr = g_strdup(match->text);
*newval_ptr = g_strdup(match_str);
assert(*newval_ptr != NULL);
xaccSetBasicCellValue(bcell, *newval_ptr);
@ -637,24 +642,27 @@ ComboDirect (BasicCell *bcell,
extra_colon = TRUE;
}
match = xaccGetQuickFillStrLen(box->qf, oldval, new_pos);
match = gnc_quickfill_get_string_len_match (box->qf, oldval, new_pos);
if (match == NULL)
return FALSE;
if (extra_colon)
{
match = xaccGetQuickFill(match, box->complete_char);
match = gnc_quickfill_get_char_match (match,
box->complete_char);
if (match == NULL)
return FALSE;
new_pos++;
}
if ((match->text != NULL) &&
(strncmp(match->text, oldval, length) == 0) &&
(strcmp(match->text, oldval) != 0))
match_str = gnc_quickfill_string (match);
if ((match_str != NULL) &&
(strncmp(match_str, oldval, length) == 0) &&
(strcmp(match_str, oldval) != 0))
{
*newval_ptr = g_strdup(match->text);
*newval_ptr = g_strdup(match_str);
assert(*newval_ptr != NULL);
xaccSetBasicCellValue(bcell, *newval_ptr);

View File

@ -44,6 +44,7 @@ QuickFillDirect (BasicCell *bcell,
{
QuickFillCell *cell = (QuickFillCell *) bcell;
GdkEventKey *event = gui_data;
const char *match_str;
QuickFill *match;
int prefix_len;
@ -71,19 +72,23 @@ QuickFillDirect (BasicCell *bcell,
(*start_selection >= *cursor_position))
*cursor_position = *end_selection;
match = xaccGetQuickFillStrLen(cell->qfRoot, oldval, *cursor_position);
match = gnc_quickfill_get_string_len_match (cell->qfRoot, oldval,
*cursor_position);
if (match == NULL)
return TRUE;
match = xaccGetQuickFillUniqueLen(match, &prefix_len);
match = gnc_quickfill_get_unique_len_match (match, &prefix_len);
if (match == NULL)
return TRUE;
if ((match->text != NULL) &&
(strncmp(match->text, oldval, strlen(oldval)) == 0) &&
(strcmp(match->text, oldval) != 0))
match_str = gnc_quickfill_string (match);
if ((match_str != NULL) &&
(strncmp(match_str, oldval, strlen(oldval)) == 0) &&
(strcmp(match_str, oldval) != 0))
{
*newval_ptr = g_strdup(match->text);
*newval_ptr = g_strdup(match_str);
assert(*newval_ptr != NULL);
xaccSetBasicCellValue(bcell, *newval_ptr);
}

View File

@ -90,6 +90,7 @@ quick_modify (BasicCell *_cell,
int *end_selection)
{
QuickFillCell *cell = (QuickFillCell *) _cell;
const char *match_str;
const char *retval;
QuickFill *match;
@ -133,9 +134,11 @@ quick_modify (BasicCell *_cell,
cell->original = NULL;
}
match = xaccGetQuickFillStr(cell->qfRoot, newval);
match = gnc_quickfill_get_string_match (cell->qfRoot, newval);
if ((match == NULL) || (match->text == NULL))
match_str = gnc_quickfill_string (match);
if ((match == NULL) || (match_str == NULL))
{
if (cell->original != NULL)
retval = g_strdup(cell->original);
@ -148,7 +151,7 @@ quick_modify (BasicCell *_cell,
return retval;
}
retval = g_strdup(match->text);
retval = g_strdup(match_str);
*start_selection = strlen(newval);
*end_selection = -1;
@ -167,7 +170,8 @@ quick_leave (BasicCell *_cell, const char *val)
QuickFillCell *cell = (QuickFillCell *) _cell;
cell->qf = cell->qfRoot;
xaccQFInsertText (cell->qfRoot, val, cell->sort);
gnc_quickfill_insert (cell->qfRoot, val, cell->sort);
return val;
}
@ -192,7 +196,7 @@ xaccInitQuickFillCell (QuickFillCell *cell)
{
xaccInitBasicCell (&(cell->cell));
cell->qfRoot = xaccMallocQuickFill();
cell->qfRoot = gnc_quickfill_new ();
cell->qf = cell->qfRoot;
cell->sort = QUICKFILL_LIFO;
cell->original = NULL;
@ -210,7 +214,7 @@ xaccInitQuickFillCell (QuickFillCell *cell)
void
xaccDestroyQuickFillCell (QuickFillCell *cell)
{
xaccFreeQuickFill (cell->qfRoot);
gnc_quickfill_destroy (cell->qfRoot);
cell->qfRoot = NULL;
cell->qf = NULL;
@ -230,7 +234,7 @@ xaccDestroyQuickFillCell (QuickFillCell *cell)
void
xaccSetQuickFillCellValue (QuickFillCell *cell, const char * value)
{
xaccQFInsertText (cell->qfRoot, value, cell->sort);
gnc_quickfill_insert (cell->qfRoot, value, cell->sort);
SET (&(cell->cell), value);
}

View File

@ -62,15 +62,18 @@ typedef struct _QuickFillCell
} QuickFillCell;
QuickFillCell * xaccMallocQuickFillCell (void);
void xaccInitQuickFillCell (QuickFillCell *);
void xaccDestroyQuickFillCell (QuickFillCell *);
void xaccInitQuickFillCell (QuickFillCell *cell);
void xaccDestroyQuickFillCell (QuickFillCell *cell);
void xaccSetQuickFillCellValue (QuickFillCell *, const char *);
void xaccSetQuickFillSort (QuickFillCell *, QuickFillSort);
void xaccSetQuickFillOriginal (QuickFillCell *, const char *);
void xaccSetQuickFillCellValue (QuickFillCell *cell,
const char *value);
void xaccSetQuickFillSort (QuickFillCell *cell,
QuickFillSort sort);
void xaccSetQuickFillOriginal (QuickFillCell *cell,
const char *original);
/* GUI-dependent */
void xaccQuickFillGUIInit (QuickFillCell *);
void xaccQuickFillGUIInit (QuickFillCell *cell);
#endif /* __QUICK_FILL_CELL_C__ */