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