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