|
Packit |
d394d9 |
/* Copyright (C) 1996 Bjoern Beutel. */
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Description. =============================================================*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Manages the storage of analysis results for faster access. */
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Includes. ================================================================*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
#include <stdio.h>
|
|
Packit |
d394d9 |
#include <stdlib.h>
|
|
Packit |
d394d9 |
#include <string.h>
|
|
Packit |
d394d9 |
#include <setjmp.h>
|
|
Packit |
d394d9 |
#include <stdarg.h>
|
|
Packit |
d394d9 |
#include <glib.h>
|
|
Packit |
d394d9 |
#include "basic.h"
|
|
Packit |
d394d9 |
#include "pools.h"
|
|
Packit |
d394d9 |
#include "values.h"
|
|
Packit |
d394d9 |
#include "avl_trees.h"
|
|
Packit |
d394d9 |
#include "cache.h"
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Types. ===================================================================*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
typedef struct cache_entry /* An entry of the cache tree. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
avl_node_t avl_node; /* A node in an AVL tree. */
|
|
Packit |
d394d9 |
struct cache_entry *prev_ref, *next_ref; /* LRU chain. */
|
|
Packit |
d394d9 |
string_t surface;
|
|
Packit |
d394d9 |
int_t feat_count; /* Number of feature structures in feat_vector. */
|
|
Packit |
d394d9 |
value_t *feat_vector; /* A vector of feature structures. */
|
|
Packit |
d394d9 |
} cache_entry_t;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Global Variables. ========================================================*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
int_t cache_accesses; /* Number of calls of "word_in_cache". */
|
|
Packit |
d394d9 |
int_t cache_hits; /* Number of successful calls of "word_in_cache". */
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Variables. ===============================================================*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
static avl_node_t *cache_tree; /* The cache tree. Actually points to
|
|
Packit |
d394d9 |
* cache_entry_t. */
|
|
Packit |
d394d9 |
static int_t max_entry_count; /* Maximum of entries in CACHE_TREE. */
|
|
Packit |
d394d9 |
static int_t entry_count; /* Actual number of entries in CACHE_TREE. */
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
static cache_entry_t *first_ref; /* The entry that was referenced first. */
|
|
Packit |
d394d9 |
static cache_entry_t *last_ref; /* The entry that was referenced last. */
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* These are needed for "next_result_in_cache". */
|
|
Packit |
d394d9 |
static cache_entry_t *current_entry;
|
|
Packit |
d394d9 |
static int_t current_result;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Functions. ===============================================================*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
static int_t
|
|
Packit |
d394d9 |
compare_cache_entries( avl_node_t *node1, avl_node_t *node2 )
|
|
Packit |
d394d9 |
/* A callback function for "avl_tree_insert", "avl_tree_remove",
|
|
Packit |
d394d9 |
* used to compare "cache_entry_t" nodes. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
return strcmp( ((cache_entry_t *) node1)->surface,
|
|
Packit |
d394d9 |
((cache_entry_t *) node2)->surface );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
static cache_entry_t *
|
|
Packit |
d394d9 |
new_cache_entry( string_t surf_start, string_t surf_end,
|
|
Packit |
d394d9 |
int_t feat_count, value_t feat_vector[] )
|
|
Packit |
d394d9 |
/* Create cache entry for string at SURF_START..SURF_END.
|
|
Packit |
d394d9 |
* It has FEAT_COUNT feature structures stored in FEAT_VECTOR.
|
|
Packit |
d394d9 |
* Return the created entry. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
cache_entry_t *cache_entry;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Allocate a cache entry. */
|
|
Packit |
d394d9 |
cache_entry = new_mem( sizeof( cache_entry_t ) );
|
|
Packit |
d394d9 |
cache_entry->surface = new_string( surf_start, surf_end );
|
|
Packit |
d394d9 |
cache_entry->feat_count = feat_count;
|
|
Packit |
d394d9 |
cache_entry->feat_vector = feat_vector;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
entry_count++;
|
|
Packit |
d394d9 |
return cache_entry;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
static void
|
|
Packit |
d394d9 |
free_cache_entry( cache_entry_t **cache_entry )
|
|
Packit |
d394d9 |
/* Free the memory allocated for *CACHE_ENTRY. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
int_t i;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
if (*cache_entry != NULL)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
for (i = 0; i < (*cache_entry)->feat_count; i++)
|
|
Packit |
d394d9 |
free_mem( &(*cache_entry)->feat_vector[i] );
|
|
Packit |
d394d9 |
free_mem( &(*cache_entry)->feat_vector );
|
|
Packit |
d394d9 |
free_mem( &(*cache_entry)->surface );
|
|
Packit |
d394d9 |
free_mem( cache_entry );
|
|
Packit |
d394d9 |
entry_count--;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
static void
|
|
Packit |
d394d9 |
reference_entry( cache_entry_t *entry )
|
|
Packit |
d394d9 |
/* Put ENTRY at end of LRU-list if it is not already there. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
if (entry != last_ref)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
/* Remove entry from old position. */
|
|
Packit |
d394d9 |
entry->next_ref->prev_ref = entry->prev_ref;
|
|
Packit |
d394d9 |
if (entry != first_ref)
|
|
Packit |
d394d9 |
entry->prev_ref->next_ref = entry->next_ref;
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
first_ref = entry->next_ref;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Enter entry in new position. */
|
|
Packit |
d394d9 |
entry->prev_ref = last_ref;
|
|
Packit |
d394d9 |
entry->next_ref = NULL;
|
|
Packit |
d394d9 |
last_ref->next_ref = entry;
|
|
Packit |
d394d9 |
last_ref = entry;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
bool_t
|
|
Packit |
d394d9 |
word_in_cache( string_t surf_start, string_t surf_end )
|
|
Packit |
d394d9 |
/* Check if word in [SURF_START..SURF_END] is in the cache.
|
|
Packit |
d394d9 |
* Return TRUE if word found. Use "next_result_in_cache" to get next result. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
cache_entry_t *entry;
|
|
Packit |
d394d9 |
int_t result;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
cache_accesses++;
|
|
Packit |
d394d9 |
entry = (cache_entry_t *) cache_tree;
|
|
Packit |
d394d9 |
while (entry != NULL)
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
result = strncmp( surf_start, entry->surface, surf_end - surf_start );
|
|
Packit |
d394d9 |
if (result == 0 && entry->surface[ surf_end - surf_start ] != EOS)
|
|
Packit |
d394d9 |
result = -1;
|
|
Packit |
d394d9 |
if (result < 0)
|
|
Packit |
d394d9 |
entry = (cache_entry_t *) entry->avl_node.left;
|
|
Packit |
d394d9 |
else if (result > 0)
|
|
Packit |
d394d9 |
entry = (cache_entry_t *) entry->avl_node.right;
|
|
Packit |
d394d9 |
else /* Word found. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
reference_entry( entry );
|
|
Packit |
d394d9 |
current_entry = entry;
|
|
Packit |
d394d9 |
current_result = 0;
|
|
Packit |
d394d9 |
cache_hits++;
|
|
Packit |
d394d9 |
return TRUE;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
return FALSE;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
value_t
|
|
Packit |
d394d9 |
next_result_in_cache( void )
|
|
Packit |
d394d9 |
/* Return the next feature structure for the word found by "word_in_cache".
|
|
Packit |
d394d9 |
* Return NULL if no more feature structure exists. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
value_t result;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
if (current_result >= current_entry->feat_count)
|
|
Packit |
d394d9 |
return NULL;
|
|
Packit |
d394d9 |
result = current_entry->feat_vector[ current_result ];
|
|
Packit |
d394d9 |
current_result++;
|
|
Packit |
d394d9 |
return result;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
static void
|
|
Packit |
d394d9 |
remove_entry_from_cache( void )
|
|
Packit |
d394d9 |
/* Delete an entry from cache. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
cache_entry_t *entry;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Remove first element from LRU list. */
|
|
Packit |
d394d9 |
entry = first_ref;
|
|
Packit |
d394d9 |
first_ref = entry->next_ref;
|
|
Packit |
d394d9 |
if (first_ref != NULL)
|
|
Packit |
d394d9 |
first_ref->prev_ref = NULL;
|
|
Packit |
d394d9 |
else
|
|
Packit |
d394d9 |
last_ref = NULL;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Remove ENTRY from tree. */
|
|
Packit |
d394d9 |
remove_avl_node( (avl_node_t *) entry, (avl_node_t **) &cache_tree,
|
|
Packit |
d394d9 |
compare_cache_entries );
|
|
Packit |
d394d9 |
free_cache_entry( &entry );
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
void
|
|
Packit |
d394d9 |
enter_in_cache( string_t surf_start, string_t surf_end,
|
|
Packit |
d394d9 |
int_t feat_count, value_t feat_vector[] )
|
|
Packit |
d394d9 |
/* Enter the word in [SURF_START..SURF_END] in the cache.
|
|
Packit |
d394d9 |
* It has FEAT_COUNT feature structures, stored in FEAT_VECTOR[].
|
|
Packit |
d394d9 |
* Be sure that the word is not yet in the cache. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
cache_entry_t *cache_entry;
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
if (entry_count >= max_entry_count)
|
|
Packit |
d394d9 |
remove_entry_from_cache();
|
|
Packit |
d394d9 |
cache_entry = new_cache_entry( surf_start, surf_end,
|
|
Packit |
d394d9 |
feat_count, feat_vector );
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Enter entry in cache tree. */
|
|
Packit |
d394d9 |
insert_avl_node( (avl_node_t *) cache_entry, (avl_node_t **) &cache_tree,
|
|
Packit |
d394d9 |
compare_cache_entries );
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* Put entry at end of LRU table. */
|
|
Packit |
d394d9 |
if (last_ref != NULL)
|
|
Packit |
d394d9 |
last_ref->next_ref = cache_entry;
|
|
Packit |
d394d9 |
cache_entry->prev_ref = last_ref;
|
|
Packit |
d394d9 |
cache_entry->next_ref = NULL;
|
|
Packit |
d394d9 |
last_ref = cache_entry;
|
|
Packit |
d394d9 |
if (first_ref == NULL)
|
|
Packit |
d394d9 |
first_ref = cache_entry;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
void
|
|
Packit |
d394d9 |
clear_cache( void )
|
|
Packit |
d394d9 |
/* Remove all entries from the cache. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
while (entry_count > 0)
|
|
Packit |
d394d9 |
remove_entry_from_cache();
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
void
|
|
Packit |
d394d9 |
set_cache_size( int_t size )
|
|
Packit |
d394d9 |
/* Set maximum number of cache entries to SIZE. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
max_entry_count = size;
|
|
Packit |
d394d9 |
while (entry_count > max_entry_count)
|
|
Packit |
d394d9 |
remove_entry_from_cache();
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
int_t
|
|
Packit |
d394d9 |
get_cache_size( void )
|
|
Packit |
d394d9 |
/* Get actual number of cache entries. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
return entry_count;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
int_t
|
|
Packit |
d394d9 |
get_cache_maximum( void )
|
|
Packit |
d394d9 |
/* Get maximum number of cache entries. */
|
|
Packit |
d394d9 |
{
|
|
Packit |
d394d9 |
return max_entry_count;
|
|
Packit |
d394d9 |
}
|
|
Packit |
d394d9 |
|
|
Packit |
d394d9 |
/* End of file. =============================================================*/
|