#include #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 (ch=NO_SPECIAL_COUNTERS) g_warning("Matching pair not found for U+%04" G_GINT32_MODIFIER "X",ch); return GINT_TO_POINTER((gint)ch); } void increment_matching(struct counters *counters,gunichar ch,gboolean open) { gpointer key,orig_key; struct matching_counter *value; if (!counters->matching) 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_reset(struct counters *counters) { if (counters->matching) g_tree_destroy(counters->matching); memset(counters,0,sizeof(*counters)); } void counters_destroy(struct counters *counters) { if (counters->matching) { g_tree_destroy(counters->matching); counters->matching=NULL; } }