From b02b52d86a49b75d876d6db33ba4e1d3e9d74986 Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 20 May 2012 00:38:16 +0100 Subject: [PATCH] Simplified autocomplete api Now stores memory management functions, passed on p_autocomplete_new --- contact_list.c | 25 ++---- prof_autocomplete.c | 83 ++++++++++---------- prof_autocomplete.h | 16 ++-- test_prof_autocomplete.c | 162 +++++++++++++++++++-------------------- 4 files changed, 135 insertions(+), 151 deletions(-) diff --git a/contact_list.c b/contact_list.c index 73d5cc8d..22122f4a 100644 --- a/contact_list.c +++ b/contact_list.c @@ -32,16 +32,16 @@ static PAutocomplete ac; -static PContact _copy(PContact contact); - void contact_list_init(void) { - ac = p_autocomplete_new(); + ac = p_autocomplete_new((PStrFunc)p_contact_name, + (PCopyFunc)p_contact_copy, + (GDestroyNotify)p_contact_free); } void contact_list_clear(void) { - p_autocomplete_clear(ac, (GDestroyNotify)p_contact_free); + p_autocomplete_clear(ac); } void reset_search_attempts(void) @@ -51,30 +51,21 @@ void reset_search_attempts(void) void contact_list_remove(const char * const name) { - p_autocomplete_remove(ac, name, (PStrFunc)p_contact_name, (GDestroyNotify)p_contact_free); + p_autocomplete_remove(ac, name); } void contact_list_add(const char * const name, const char * const show, const char * const status) { - p_autocomplete_add(ac, p_contact_new(name, show, status), (PStrFunc)p_contact_name, - (GDestroyNotify)p_contact_free); + p_autocomplete_add(ac, p_contact_new(name, show, status)); } GSList * get_contact_list(void) { - return p_autocomplete_get_list(ac, (PCopyFunc)_copy); + return p_autocomplete_get_list(ac); } char * find_contact(char *search_str) { - return p_autocomplete_complete(ac, search_str, (PStrFunc)p_contact_name); + return p_autocomplete_complete(ac, search_str); } - -static PContact _copy(PContact contact) -{ - return p_contact_new(p_contact_name(contact), - p_contact_show(contact), - p_contact_status(contact)); -} - diff --git a/prof_autocomplete.c b/prof_autocomplete.c index ec6b4e23..6996f4fd 100644 --- a/prof_autocomplete.c +++ b/prof_autocomplete.c @@ -32,28 +32,44 @@ struct p_autocomplete_t { GSList *items; GSList *last_found; gchar *search_str; + PStrFunc str_func; + PCopyFunc copy_func; + GDestroyNotify free_func; }; -static gchar * _search_from(PAutocomplete ac, GSList *curr, PStrFunc str_func); +static gchar * _search_from(PAutocomplete ac, GSList *curr); static const char *_str_func_default(const char *orig); static const char *_copy_func_default(const char *orig); -PAutocomplete p_autocomplete_new(void) +PAutocomplete p_autocomplete_new(PStrFunc str_func, PCopyFunc copy_func, + GDestroyNotify free_func) { PAutocomplete new = malloc(sizeof(struct p_autocomplete_t)); new->items = NULL; new->last_found = NULL; new->search_str = NULL; + if (str_func) + new->str_func = str_func; + else + new->str_func = (PStrFunc)_str_func_default; + + if (copy_func) + new->copy_func = copy_func; + else + new->copy_func = (PCopyFunc)_copy_func_default; + + if (free_func) + new->free_func = free_func; + else + new->free_func = (GDestroyNotify)free; + return new; } -void p_autocomplete_clear(PAutocomplete ac, GDestroyNotify free_func) +void p_autocomplete_clear(PAutocomplete ac) { - if (free_func == NULL) - free_func = (GDestroyNotify)free; - - g_slist_free_full(ac->items, free_func); + g_slist_free_full(ac->items, ac->free_func); ac->items = NULL; p_autocomplete_reset(ac); @@ -68,14 +84,8 @@ void p_autocomplete_reset(PAutocomplete ac) } } -void p_autocomplete_add(PAutocomplete ac, void *item, PStrFunc str_func, - GDestroyNotify free_func) +void p_autocomplete_add(PAutocomplete ac, void *item) { - if (str_func == NULL) - str_func = (PStrFunc)_str_func_default; - if (free_func == NULL) - free_func = (GDestroyNotify)free; - if (ac->items == NULL) { ac->items = g_slist_append(ac->items, item); return; @@ -85,14 +95,14 @@ void p_autocomplete_add(PAutocomplete ac, void *item, PStrFunc str_func, while(curr) { // insert - if (g_strcmp0(str_func(curr->data), str_func(item)) > 0) { + if (g_strcmp0(ac->str_func(curr->data), ac->str_func(item)) > 0) { ac->items = g_slist_insert_before(ac->items, curr, item); return; // update - } else if (g_strcmp0(str_func(curr->data), str_func(item)) == 0) { - free_func(curr->data); + } else if (g_strcmp0(ac->str_func(curr->data), ac->str_func(item)) == 0) { + ac->free_func(curr->data); curr->data = item; return; } @@ -107,15 +117,11 @@ void p_autocomplete_add(PAutocomplete ac, void *item, PStrFunc str_func, } } -void p_autocomplete_remove(PAutocomplete ac, const char * const item, - PStrFunc str_func, GDestroyNotify free_func) +void p_autocomplete_remove(PAutocomplete ac, const char * const item) { - if (str_func == NULL) - str_func = (PStrFunc)_str_func_default; - // reset last found if it points to the item to be removed if (ac->last_found != NULL) - if (g_strcmp0(str_func(ac->last_found->data), item) == 0) + if (g_strcmp0(ac->str_func(ac->last_found->data), item) == 0) ac->last_found = NULL; if (!ac->items) { @@ -124,10 +130,10 @@ void p_autocomplete_remove(PAutocomplete ac, const char * const item, GSList *curr = ac->items; while(curr) { - if (g_strcmp0(str_func(curr->data), item) == 0) { + if (g_strcmp0(ac->str_func(curr->data), item) == 0) { void *current_item = curr->data; ac->items = g_slist_remove(ac->items, curr->data); - free_func(current_item); + ac->free_func(current_item); return; } @@ -139,28 +145,21 @@ void p_autocomplete_remove(PAutocomplete ac, const char * const item, } } -GSList * p_autocomplete_get_list(PAutocomplete ac, PCopyFunc copy_func) +GSList * p_autocomplete_get_list(PAutocomplete ac) { - if (copy_func == NULL) - copy_func = (PCopyFunc)_copy_func_default; - GSList *copy = NULL; GSList *curr = ac->items; while(curr) { - copy = g_slist_append(copy, copy_func(curr->data)); + copy = g_slist_append(copy, ac->copy_func(curr->data)); curr = g_slist_next(curr); } return copy; } -gchar * p_autocomplete_complete(PAutocomplete ac, gchar *search_str, - PStrFunc str_func) +gchar * p_autocomplete_complete(PAutocomplete ac, gchar *search_str) { - if (str_func == NULL) - str_func = (PStrFunc)_str_func_default; - gchar *found = NULL; // no items to search @@ -173,18 +172,18 @@ gchar * p_autocomplete_complete(PAutocomplete ac, gchar *search_str, (gchar *) malloc((strlen(search_str) + 1) * sizeof(gchar)); strcpy(ac->search_str, search_str); - found = _search_from(ac, ac->items, str_func); + found = _search_from(ac, ac->items); return found; // subsequent search attempt } else { // search from here+1 tp end - found = _search_from(ac, g_slist_next(ac->last_found), str_func); + found = _search_from(ac, g_slist_next(ac->last_found)); if (found != NULL) return found; // search from beginning - found = _search_from(ac, ac->items, str_func); + found = _search_from(ac, ac->items); if (found != NULL) return found; @@ -194,22 +193,22 @@ gchar * p_autocomplete_complete(PAutocomplete ac, gchar *search_str, } } -static gchar * _search_from(PAutocomplete ac, GSList *curr, PStrFunc str_func) +static gchar * _search_from(PAutocomplete ac, GSList *curr) { while(curr) { // match found - if (strncmp(str_func(curr->data), + if (strncmp(ac->str_func(curr->data), ac->search_str, strlen(ac->search_str)) == 0) { gchar *result = - (gchar *) malloc((strlen(str_func(curr->data)) + 1) * sizeof(gchar)); + (gchar *) malloc((strlen(ac->str_func(curr->data)) + 1) * sizeof(gchar)); // set pointer to last found ac->last_found = curr; // return the string, must be free'd by caller - strcpy(result, str_func(curr->data)); + strcpy(result, ac->str_func(curr->data)); return result; } diff --git a/prof_autocomplete.h b/prof_autocomplete.h index fa323502..5f89d207 100644 --- a/prof_autocomplete.h +++ b/prof_autocomplete.h @@ -29,15 +29,13 @@ typedef struct p_autocomplete_t *PAutocomplete; typedef const char * (*PStrFunc)(const void *obj); typedef void * (*PCopyFunc)(const void *obj); -PAutocomplete p_autocomplete_new(void); -void p_autocomplete_clear(PAutocomplete ac, GDestroyNotify free_func); -void p_autocomplete_reset(PAutocomplete ac); -void p_autocomplete_add(PAutocomplete ac, void *item, PStrFunc str_func, +PAutocomplete p_autocomplete_new(PStrFunc str_func, PCopyFunc copy_func, GDestroyNotify free_func); -void p_autocomplete_remove(PAutocomplete ac, const char * const item, - PStrFunc str_func, GDestroyNotify free_func); -GSList * p_autocomplete_get_list(PAutocomplete ac, PCopyFunc copy_func); -gchar * p_autocomplete_complete(PAutocomplete ac, gchar *search_str, - PStrFunc str_func); +void p_autocomplete_clear(PAutocomplete ac); +void p_autocomplete_reset(PAutocomplete ac); +void p_autocomplete_add(PAutocomplete ac, void *item); +void p_autocomplete_remove(PAutocomplete ac, const char * const item); +GSList * p_autocomplete_get_list(PAutocomplete ac); +gchar * p_autocomplete_complete(PAutocomplete ac, gchar *search_str); #endif diff --git a/test_prof_autocomplete.c b/test_prof_autocomplete.c index ef867ff7..82e57eae 100644 --- a/test_prof_autocomplete.c +++ b/test_prof_autocomplete.c @@ -9,205 +9,202 @@ static void clear_empty(void) { - PAutocomplete ac = p_autocomplete_new(); - p_autocomplete_clear(ac, NULL); + PAutocomplete ac = p_autocomplete_new(NULL, NULL, NULL); + p_autocomplete_clear(ac); } static void clear_empty_with_free_func(void) { - PAutocomplete ac = p_autocomplete_new(); - p_autocomplete_clear(ac, (GDestroyNotify)p_contact_free); + PAutocomplete ac = p_autocomplete_new(NULL, NULL, (GDestroyNotify)p_contact_free); + p_autocomplete_clear(ac); } static void reset_after_create(void) { - PAutocomplete ac = p_autocomplete_new(); + PAutocomplete ac = p_autocomplete_new(NULL, NULL, NULL); p_autocomplete_reset(ac); - p_autocomplete_clear(ac, NULL); + p_autocomplete_clear(ac); } static void find_after_create(void) { - PAutocomplete ac = p_autocomplete_new(); - p_autocomplete_complete(ac, "hello", NULL); - p_autocomplete_clear(ac, NULL); + PAutocomplete ac = p_autocomplete_new(NULL, NULL, NULL); + p_autocomplete_complete(ac, "hello"); + p_autocomplete_clear(ac); } static void get_after_create_returns_null(void) { - PAutocomplete ac = p_autocomplete_new(); - GSList *result = p_autocomplete_get_list(ac, NULL); + PAutocomplete ac = p_autocomplete_new(NULL, NULL, NULL); + GSList *result = p_autocomplete_get_list(ac); assert_is_null(result); - p_autocomplete_clear(ac, NULL); + p_autocomplete_clear(ac); } static void get_after_create_with_copy_func_returns_null(void) { - PAutocomplete ac = p_autocomplete_new(); - GSList *result = p_autocomplete_get_list(ac, (PCopyFunc)p_contact_copy); + PAutocomplete ac = p_autocomplete_new(NULL, (PCopyFunc)p_contact_copy, + (GDestroyNotify)p_contact_free); + GSList *result = p_autocomplete_get_list(ac); assert_is_null(result); - p_autocomplete_clear(ac, (GDestroyNotify)p_contact_free); + p_autocomplete_clear(ac); } static void add_one_and_complete(void) { char *item = strdup("Hello"); - PAutocomplete ac = p_autocomplete_new(); - p_autocomplete_add(ac, item, NULL, NULL); - char *result = p_autocomplete_complete(ac, "Hel", NULL); + PAutocomplete ac = p_autocomplete_new(NULL, NULL, NULL); + p_autocomplete_add(ac, item); + char *result = p_autocomplete_complete(ac, "Hel"); assert_string_equals("Hello", result); - p_autocomplete_clear(ac, NULL); + p_autocomplete_clear(ac); } static void add_one_and_complete_with_funcs(void) { PContact contact = p_contact_new("James", "Online", "I'm here"); - PAutocomplete ac = p_autocomplete_new(); - p_autocomplete_add(ac, contact, (PStrFunc)p_contact_name, + PAutocomplete ac = p_autocomplete_new((PStrFunc)p_contact_name, NULL, (GDestroyNotify)p_contact_free); - char *result = p_autocomplete_complete(ac, "Jam", (PStrFunc)p_contact_name); + p_autocomplete_add(ac, contact); + char *result = p_autocomplete_complete(ac, "Jam"); assert_string_equals("James", result); - p_autocomplete_clear(ac, (GDestroyNotify)p_contact_free); + p_autocomplete_clear(ac); } static void add_two_and_complete_returns_first(void) { char *item1 = strdup("Hello"); char *item2 = strdup("Help"); - PAutocomplete ac = p_autocomplete_new(); - p_autocomplete_add(ac, item1, NULL, NULL); - p_autocomplete_add(ac, item2, NULL, NULL); - char *result = p_autocomplete_complete(ac, "Hel", NULL); + PAutocomplete ac = p_autocomplete_new(NULL, NULL, NULL); + p_autocomplete_add(ac, item1); + p_autocomplete_add(ac, item2); + char *result = p_autocomplete_complete(ac, "Hel"); assert_string_equals("Hello", result); - p_autocomplete_clear(ac, NULL); + p_autocomplete_clear(ac); } static void add_two_and_complete_returns_first_with_funcs(void) { PContact contact1 = p_contact_new("James", "Online", "I'm here"); PContact contact2 = p_contact_new("Jamie", "Away", "Out to lunch"); - PAutocomplete ac = p_autocomplete_new(); - p_autocomplete_add(ac, contact1, (PStrFunc)p_contact_name, + PAutocomplete ac = p_autocomplete_new((PStrFunc)p_contact_name, NULL, (GDestroyNotify)p_contact_free); - p_autocomplete_add(ac, contact2, (PStrFunc)p_contact_name, - (GDestroyNotify)p_contact_free); - char *result = p_autocomplete_complete(ac, "Jam", (PStrFunc)p_contact_name); + p_autocomplete_add(ac, contact1); + p_autocomplete_add(ac, contact2); + char *result = p_autocomplete_complete(ac, "Jam"); assert_string_equals("James", result); - p_autocomplete_clear(ac, (GDestroyNotify)p_contact_free); + p_autocomplete_clear(ac); } static void add_two_and_complete_returns_second(void) { char *item1 = strdup("Hello"); char *item2 = strdup("Help"); - PAutocomplete ac = p_autocomplete_new(); - p_autocomplete_add(ac, item1, NULL, NULL); - p_autocomplete_add(ac, item2, NULL, NULL); - char *result1 = p_autocomplete_complete(ac, "Hel", NULL); - char *result2 = p_autocomplete_complete(ac, result1, NULL); + PAutocomplete ac = p_autocomplete_new(NULL, NULL, NULL); + p_autocomplete_add(ac, item1); + p_autocomplete_add(ac, item2); + char *result1 = p_autocomplete_complete(ac, "Hel"); + char *result2 = p_autocomplete_complete(ac, result1); assert_string_equals("Help", result2); - p_autocomplete_clear(ac, NULL); + p_autocomplete_clear(ac); } static void add_two_and_complete_returns_second_with_funcs(void) { PContact contact1 = p_contact_new("James", "Online", "I'm here"); PContact contact2 = p_contact_new("Jamie", "Away", "Out to lunch"); - PAutocomplete ac = p_autocomplete_new(); - p_autocomplete_add(ac, contact1, (PStrFunc)p_contact_name, + PAutocomplete ac = p_autocomplete_new((PStrFunc)p_contact_name, NULL, (GDestroyNotify)p_contact_free); - p_autocomplete_add(ac, contact2, (PStrFunc)p_contact_name, - (GDestroyNotify)p_contact_free); - char *result1 = p_autocomplete_complete(ac, "Jam", (PStrFunc)p_contact_name); - char *result2 = p_autocomplete_complete(ac, result1, (PStrFunc)p_contact_name); + p_autocomplete_add(ac, contact1); + p_autocomplete_add(ac, contact2); + char *result1 = p_autocomplete_complete(ac, "Jam"); + char *result2 = p_autocomplete_complete(ac, result1); assert_string_equals("Jamie", result2); - p_autocomplete_clear(ac, (GDestroyNotify)p_contact_free); + p_autocomplete_clear(ac); } static void add_two_adds_two(void) { char *item1 = strdup("Hello"); char *item2 = strdup("Help"); - PAutocomplete ac = p_autocomplete_new(); - p_autocomplete_add(ac, item1, NULL, NULL); - p_autocomplete_add(ac, item2, NULL, NULL); - GSList *result = p_autocomplete_get_list(ac, NULL); + PAutocomplete ac = p_autocomplete_new(NULL, NULL, NULL); + p_autocomplete_add(ac, item1); + p_autocomplete_add(ac, item2); + GSList *result = p_autocomplete_get_list(ac); assert_int_equals(2, g_slist_length(result)); - p_autocomplete_clear(ac, NULL); + p_autocomplete_clear(ac); } static void add_two_adds_two_with_funcs(void) { PContact contact1 = p_contact_new("James", "Online", "I'm here"); PContact contact2 = p_contact_new("Jamie", "Away", "Out to lunch"); - PAutocomplete ac = p_autocomplete_new(); - p_autocomplete_add(ac, contact1, (PStrFunc)p_contact_name, - (GDestroyNotify)p_contact_free); - p_autocomplete_add(ac, contact2, (PStrFunc)p_contact_name, - (GDestroyNotify)p_contact_free); - GSList *result = p_autocomplete_get_list(ac, (PCopyFunc)p_contact_copy); + PAutocomplete ac = p_autocomplete_new((PStrFunc)p_contact_name, + (PCopyFunc)p_contact_copy, (GDestroyNotify)p_contact_free); + p_autocomplete_add(ac, contact1); + p_autocomplete_add(ac, contact2); + GSList *result = p_autocomplete_get_list(ac); assert_int_equals(2, g_slist_length(result)); - p_autocomplete_clear(ac, (GDestroyNotify)p_contact_free); + p_autocomplete_clear(ac); } static void add_two_same_adds_one(void) { char *item1 = strdup("Hello"); char *item2 = strdup("Hello"); - PAutocomplete ac = p_autocomplete_new(); - p_autocomplete_add(ac, item1, NULL, NULL); - p_autocomplete_add(ac, item2, NULL, NULL); - GSList *result = p_autocomplete_get_list(ac, NULL); + PAutocomplete ac = p_autocomplete_new(NULL, NULL, NULL); + p_autocomplete_add(ac, item1); + p_autocomplete_add(ac, item2); + GSList *result = p_autocomplete_get_list(ac); assert_int_equals(1, g_slist_length(result)); - p_autocomplete_clear(ac, NULL); + p_autocomplete_clear(ac); } static void add_two_same_adds_one_with_funcs(void) { PContact contact1 = p_contact_new("James", "Online", "I'm here"); PContact contact2 = p_contact_new("James", "Away", "Out to lunch"); - PAutocomplete ac = p_autocomplete_new(); - p_autocomplete_add(ac, contact1, (PStrFunc)p_contact_name, - (GDestroyNotify)p_contact_free); - p_autocomplete_add(ac, contact2, (PStrFunc)p_contact_name, - (GDestroyNotify)p_contact_free); - GSList *result = p_autocomplete_get_list(ac, (PCopyFunc)p_contact_copy); + PAutocomplete ac = p_autocomplete_new((PStrFunc)p_contact_name, + (PCopyFunc)p_contact_copy, (GDestroyNotify)p_contact_free); + p_autocomplete_add(ac, contact1); + p_autocomplete_add(ac, contact2); + GSList *result = p_autocomplete_get_list(ac); assert_int_equals(1, g_slist_length(result)); - p_autocomplete_clear(ac, (GDestroyNotify)p_contact_free); + p_autocomplete_clear(ac); } static void add_two_same_updates(void) { char *item1 = strdup("Hello"); char *item2 = strdup("Hello"); - PAutocomplete ac = p_autocomplete_new(); - p_autocomplete_add(ac, item1, NULL, NULL); - p_autocomplete_add(ac, item2, NULL, NULL); - GSList *result = p_autocomplete_get_list(ac, NULL); + PAutocomplete ac = p_autocomplete_new(NULL, NULL, NULL); + p_autocomplete_add(ac, item1); + p_autocomplete_add(ac, item2); + GSList *result = p_autocomplete_get_list(ac); GSList *first = g_slist_nth(result, 0); @@ -215,19 +212,18 @@ static void add_two_same_updates(void) assert_string_equals("Hello", str); - p_autocomplete_clear(ac, NULL); + p_autocomplete_clear(ac); } static void add_two_same_updates_with_funcs(void) { PContact contact1 = p_contact_new("James", "Online", "I'm here"); PContact contact2 = p_contact_new("James", "Away", "Out to lunch"); - PAutocomplete ac = p_autocomplete_new(); - p_autocomplete_add(ac, contact1, (PStrFunc)p_contact_name, - (GDestroyNotify)p_contact_free); - p_autocomplete_add(ac, contact2, (PStrFunc)p_contact_name, - (GDestroyNotify)p_contact_free); - GSList *result = p_autocomplete_get_list(ac, (PCopyFunc)p_contact_copy); + PAutocomplete ac = p_autocomplete_new((PStrFunc)p_contact_name, + (PCopyFunc)p_contact_copy, (GDestroyNotify)p_contact_free); + p_autocomplete_add(ac, contact1); + p_autocomplete_add(ac, contact2); + GSList *result = p_autocomplete_get_list(ac); GSList *first = g_slist_nth(result, 0); PContact contact = first->data; @@ -236,7 +232,7 @@ static void add_two_same_updates_with_funcs(void) assert_string_equals("Away", p_contact_show(contact)); assert_string_equals("Out to lunch", p_contact_status(contact)); - p_autocomplete_clear(ac, (GDestroyNotify)p_contact_free); + p_autocomplete_clear(ac); } void register_prof_autocomplete_tests(void)