bookloupe/counters.c
author ali <ali@juiblex.co.uk>
Tue Sep 24 22:31:04 2013 +0100 (2013-09-24)
changeset 113 27e126ac2e8f
parent 103 adc06e9e8470
permissions -rw-r--r--
Update documentation for 2.0.54
     1 #include <stdlib.h>
     2 #include <string.h>
     3 #include <glib.h>
     4 #include "bookloupe.h"
     5 #include "counters.h"
     6 
     7 struct matching_counter {
     8     int open,close;
     9 };
    10 
    11 static struct matching_counter *matching_counter_new(void)
    12 {
    13     return g_slice_new0(struct matching_counter);
    14 }
    15 
    16 static void matching_counter_free(struct matching_counter *counter)
    17 {
    18     g_slice_free(struct matching_counter,counter);
    19 }
    20 
    21 static gint compar_unichars(gconstpointer a,gconstpointer b,gpointer unused)
    22 {
    23     /*
    24      * Unicode code points only go up to 0x10FFFF and thus this cannot overflow.
    25      */
    26     return GPOINTER_TO_INT(a)-GPOINTER_TO_INT(b);
    27 }
    28 
    29 /*
    30  * For matching characters, we maintain a count of the opens and closes.
    31  * In the simplest case, we are dealing with a matching pair such as [ and ]
    32  * where there is a 1:1 mapping between an instance of [ with an open and
    33  * between an instance of ] with a close. matching_ket() is
    34  * responsible for selecting an arbitary base character of a matching pair.
    35  */
    36 static gpointer matching_key(gunichar ch)
    37 {
    38     gunichar mirrored;
    39     if (g_unichar_get_mirror_char(ch,&mirrored))
    40 	if (ch<mirrored)
    41 	    return GINT_TO_POINTER((gint)ch);
    42 	else
    43 	    return GINT_TO_POINTER((gint)mirrored);
    44     else if (ch==CHAR_SQUOTE || ch==CHAR_OPEN_SQUOTE)
    45 	return GINT_TO_POINTER((gint)CHAR_SQUOTE);
    46     else if (ch==CHAR_LS_QUOTE || ch==CHAR_RS_QUOTE)
    47 	return GINT_TO_POINTER((gint)CHAR_LS_QUOTE);
    48     else if (ch==CHAR_LD_QUOTE || ch==CHAR_RD_QUOTE)
    49 	return GINT_TO_POINTER((gint)CHAR_LD_QUOTE);
    50     else if (ch==CHAR_DQUOTE)
    51 	return GINT_TO_POINTER((gint)ch);
    52     else if (ch<0x4000 || ch-0x4000>=NO_SPECIAL_COUNTERS)
    53 	g_warning("Matching pair not found for U+%04" G_GINT32_MODIFIER "X",ch);
    54     return GINT_TO_POINTER((gint)ch);
    55 }
    56 
    57 void increment_matching(struct counters *counters,gunichar ch,gboolean open)
    58 {
    59     gpointer key,orig_key;
    60     struct matching_counter *value;
    61     if (!counters->matching)
    62 	counters->matching=g_tree_new_full(compar_unichars,NULL,NULL,
    63 	  (GDestroyNotify)matching_counter_free);
    64     key=matching_key(ch);
    65     if (!g_tree_lookup_extended(counters->matching,key,&orig_key,
    66       (gpointer *)&value))
    67     {
    68 	value=matching_counter_new();
    69 	g_tree_insert(counters->matching,key,value);
    70     }
    71     if (open)
    72 	value->open++;
    73     else
    74 	value->close++;
    75 }
    76 
    77 int matching_count(const struct counters *counters,gunichar ch,gboolean open)
    78 {
    79     struct matching_counter *value;
    80     if (!counters->matching)
    81 	return 0;
    82     value=g_tree_lookup(counters->matching,matching_key(ch));
    83     if (!value)
    84 	return 0;
    85     return open?value->open:value->close;
    86 }
    87 
    88 /*
    89  * Return open count - closed count
    90  */
    91 int matching_difference(const struct counters *counters,gunichar ch)
    92 {
    93     struct matching_counter *value;
    94     if (!counters->matching)
    95 	return 0;
    96     value=g_tree_lookup(counters->matching,matching_key(ch));
    97     if (!value)
    98 	return 0;
    99     return value->open-value->close;
   100 }
   101 
   102 void counters_reset(struct counters *counters)
   103 {
   104     if (counters->matching)
   105 	g_tree_destroy(counters->matching);
   106     memset(counters,0,sizeof(*counters));
   107 }
   108 
   109 void counters_destroy(struct counters *counters)
   110 {
   111     if (counters->matching)
   112     {
   113 	g_tree_destroy(counters->matching);
   114 	counters->matching=NULL;
   115     }
   116 }