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