1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/bookloupe/counters.c Sat Sep 21 18:28:40 2013 +0100
1.3 @@ -0,0 +1,106 @@
1.4 +#include <stdlib.h>
1.5 +#include <glib.h>
1.6 +#include "bookloupe.h"
1.7 +#include "counters.h"
1.8 +
1.9 +struct matching_counter {
1.10 + int open,close;
1.11 +};
1.12 +
1.13 +static struct matching_counter *matching_counter_new(void)
1.14 +{
1.15 + return g_slice_new0(struct matching_counter);
1.16 +}
1.17 +
1.18 +static void matching_counter_free(struct matching_counter *counter)
1.19 +{
1.20 + g_slice_free(struct matching_counter,counter);
1.21 +}
1.22 +
1.23 +static gint compar_unichars(gconstpointer a,gconstpointer b,gpointer unused)
1.24 +{
1.25 + /*
1.26 + * Unicode code points only go up to 0x10FFFF and thus this cannot overflow.
1.27 + */
1.28 + return GPOINTER_TO_INT(a)-GPOINTER_TO_INT(b);
1.29 +}
1.30 +
1.31 +/*
1.32 + * For matching characters, we maintain a count of the opens and closes.
1.33 + * In the simplest case, we are dealing with a matching pair such as [ and ]
1.34 + * where there is a 1:1 mapping between an instance of [ with an open and
1.35 + * between an instance of ] with a close. matching_ket() is
1.36 + * responsible for selecting an arbitary base character of a matching pair.
1.37 + */
1.38 +static gpointer matching_key(gunichar ch)
1.39 +{
1.40 + gunichar mirrored;
1.41 + if (g_unichar_get_mirror_char(ch,&mirrored))
1.42 + if (ch<mirrored)
1.43 + return GINT_TO_POINTER((gint)ch);
1.44 + else
1.45 + return GINT_TO_POINTER((gint)mirrored);
1.46 + else if (ch==CHAR_SQUOTE || ch==CHAR_OPEN_SQUOTE)
1.47 + return GINT_TO_POINTER((gint)CHAR_SQUOTE);
1.48 + else if (ch==CHAR_LS_QUOTE || ch==CHAR_RS_QUOTE)
1.49 + return GINT_TO_POINTER((gint)CHAR_LS_QUOTE);
1.50 + else
1.51 + {
1.52 + g_warning("Matching pair not found for U+%04"G_GINT32_FORMAT"X",ch);
1.53 + return GINT_TO_POINTER((gint)ch);
1.54 + }
1.55 +}
1.56 +
1.57 +void increment_matching(struct counters *counters,gunichar ch,gboolean open)
1.58 +{
1.59 + gpointer key,orig_key;
1.60 + struct matching_counter *value;
1.61 + if (!counters->matching)
1.62 + counters->matching=g_tree_new_full(compar_unichars,NULL,NULL,
1.63 + (GDestroyNotify)matching_counter_free);
1.64 + key=matching_key(ch);
1.65 + if (!g_tree_lookup_extended(counters->matching,key,&orig_key,
1.66 + (gpointer *)&value))
1.67 + {
1.68 + value=matching_counter_new();
1.69 + g_tree_insert(counters->matching,key,value);
1.70 + }
1.71 + if (open)
1.72 + value->open++;
1.73 + else
1.74 + value->close++;
1.75 +}
1.76 +
1.77 +int matching_count(const struct counters *counters,gunichar ch,gboolean open)
1.78 +{
1.79 + struct matching_counter *value;
1.80 + if (!counters->matching)
1.81 + return 0;
1.82 + value=g_tree_lookup(counters->matching,matching_key(ch));
1.83 + if (!value)
1.84 + return 0;
1.85 + return open?value->open:value->close;
1.86 +}
1.87 +
1.88 +/*
1.89 + * Return open count - closed count
1.90 + */
1.91 +int matching_difference(const struct counters *counters,gunichar ch)
1.92 +{
1.93 + struct matching_counter *value;
1.94 + if (!counters->matching)
1.95 + return 0;
1.96 + value=g_tree_lookup(counters->matching,matching_key(ch));
1.97 + if (!value)
1.98 + return 0;
1.99 + return value->open-value->close;
1.100 +}
1.101 +
1.102 +void counters_destroy(struct counters *counters)
1.103 +{
1.104 + if (counters->matching)
1.105 + {
1.106 + g_tree_destroy(counters->matching);
1.107 + counters->matching=NULL;
1.108 + }
1.109 +}