diff -r 000000000000 -r 3f655b1b0d93 bookloupe/counters.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bookloupe/counters.c Sat Sep 21 18:28:40 2013 +0100 @@ -0,0 +1,106 @@ +#include +#include +#include "bookloupe.h" +#include "counters.h" + +struct matching_counter { + int open,close; +}; + +static struct matching_counter *matching_counter_new(void) +{ + return g_slice_new0(struct matching_counter); +} + +static void matching_counter_free(struct matching_counter *counter) +{ + g_slice_free(struct matching_counter,counter); +} + +static gint compar_unichars(gconstpointer a,gconstpointer b,gpointer unused) +{ + /* + * Unicode code points only go up to 0x10FFFF and thus this cannot overflow. + */ + return GPOINTER_TO_INT(a)-GPOINTER_TO_INT(b); +} + +/* + * For matching characters, we maintain a count of the opens and closes. + * In the simplest case, we are dealing with a matching pair such as [ and ] + * where there is a 1:1 mapping between an instance of [ with an open and + * between an instance of ] with a close. matching_ket() is + * responsible for selecting an arbitary base character of a matching pair. + */ +static gpointer matching_key(gunichar ch) +{ + gunichar mirrored; + if (g_unichar_get_mirror_char(ch,&mirrored)) + if (chmatching) + counters->matching=g_tree_new_full(compar_unichars,NULL,NULL, + (GDestroyNotify)matching_counter_free); + key=matching_key(ch); + if (!g_tree_lookup_extended(counters->matching,key,&orig_key, + (gpointer *)&value)) + { + value=matching_counter_new(); + g_tree_insert(counters->matching,key,value); + } + if (open) + value->open++; + else + value->close++; +} + +int matching_count(const struct counters *counters,gunichar ch,gboolean open) +{ + struct matching_counter *value; + if (!counters->matching) + return 0; + value=g_tree_lookup(counters->matching,matching_key(ch)); + if (!value) + return 0; + return open?value->open:value->close; +} + +/* + * Return open count - closed count + */ +int matching_difference(const struct counters *counters,gunichar ch) +{ + struct matching_counter *value; + if (!counters->matching) + return 0; + value=g_tree_lookup(counters->matching,matching_key(ch)); + if (!value) + return 0; + return value->open-value->close; +} + +void counters_destroy(struct counters *counters) +{ + if (counters->matching) + { + g_tree_destroy(counters->matching); + counters->matching=NULL; + } +}