1494 lines
44 KiB
C
1494 lines
44 KiB
C
/*********************************************
|
|
File: core_tries.c
|
|
Author: Ricardo Rocha
|
|
Comments: Tries core module for Yap Prolog
|
|
version: $ID$
|
|
*********************************************/
|
|
|
|
|
|
|
|
/* -------------------------- */
|
|
/* Includes */
|
|
/* -------------------------- */
|
|
|
|
#include <YapInterface.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "core_tries.h"
|
|
|
|
|
|
|
|
/* -------------------------- */
|
|
/* Local Procedures */
|
|
/* -------------------------- */
|
|
|
|
static TrNode put_entry(TrNode node, YAP_Term entry);
|
|
static TrNode check_entry(TrNode node, YAP_Term entry);
|
|
static YAP_Term get_entry(TrNode node, YAP_Term *stack_list, TrNode *cur_node);
|
|
static void remove_entry(TrNode node);
|
|
static void remove_child_nodes(TrNode node);
|
|
static TrNode copy_child_nodes(TrNode parent_dest, TrNode node_source);
|
|
static void traverse_and_add(TrNode parent_dest, TrNode parent_source);
|
|
static void traverse_and_join(TrNode parent_dest, TrNode parent_source);
|
|
static void traverse_and_intersect(TrNode parent_dest, TrNode parent_source);
|
|
static YAP_Int traverse_and_count_common_entries(TrNode parent1, TrNode parent2);
|
|
static YAP_Int traverse_and_count_entries(TrNode node);
|
|
static void traverse_and_get_usage(TrNode node, YAP_Int depth);
|
|
static void traverse_and_save(TrNode node, FILE *file, int float_block);
|
|
static void traverse_and_load(TrNode parent, FILE *file);
|
|
static void traverse_and_print(TrNode node, YAP_Int *arity, char *str, int str_index, int mode);
|
|
|
|
|
|
|
|
/* -------------------------- */
|
|
/* Local Variables */
|
|
/* -------------------------- */
|
|
|
|
static TrEngine CURRENT_TRIE_ENGINE;
|
|
static YAP_Int USAGE_ENTRIES, USAGE_NODES, USAGE_VIRTUAL_NODES;
|
|
static YAP_Int CURRENT_AUXILIARY_TERM_STACK_SIZE, CURRENT_TRIE_MODE, CURRENT_LOAD_VERSION, CURRENT_DEPTH, CURRENT_INDEX;
|
|
static YAP_Term *AUXILIARY_TERM_STACK;
|
|
static YAP_Term *stack_args, *stack_args_base, *stack_vars, *stack_vars_base;
|
|
static YAP_Functor FunctorComma;
|
|
static void (*DATA_SAVE_FUNCTION)(TrNode, FILE *);
|
|
static void (*DATA_LOAD_FUNCTION)(TrNode, YAP_Int, FILE *);
|
|
static void (*DATA_PRINT_FUNCTION)(TrNode);
|
|
static void (*DATA_ADD_FUNCTION)(TrNode, TrNode);
|
|
static void (*DATA_COPY_FUNCTION)(TrNode, TrNode);
|
|
static void (*DATA_DESTRUCT_FUNCTION)(TrNode);
|
|
|
|
|
|
|
|
/* -------------------------- */
|
|
/* Inline Procedures */
|
|
/* -------------------------- */
|
|
|
|
static inline
|
|
TrNode trie_node_check_insert(TrNode parent, YAP_Term t) {
|
|
TrNode child;
|
|
|
|
CURRENT_DEPTH++;
|
|
child = TrNode_child(parent);
|
|
if (child == NULL) {
|
|
new_trie_node(child, t, parent, NULL, NULL, NULL);
|
|
TrNode_child(parent) = child;
|
|
} else if (IS_HASH_NODE(child)) {
|
|
TrHash hash;
|
|
TrNode *bucket;
|
|
int count;
|
|
hash = (TrHash) child;
|
|
bucket = TrHash_bucket(hash, HASH_TERM(t, TrHash_seed(hash)));
|
|
child = *bucket;
|
|
count = 0;
|
|
while (child) {
|
|
if (TrNode_entry(child) == t)
|
|
return child;
|
|
count++;
|
|
child = TrNode_next(child);
|
|
} while (child);
|
|
TrHash_num_nodes(hash)++;
|
|
new_trie_node(child, t, parent, NULL, *bucket, AS_TR_NODE_NEXT(bucket));
|
|
if (*bucket)
|
|
TrNode_previous(*bucket) = child;
|
|
*bucket = child;
|
|
if (count > MAX_NODES_PER_BUCKET && TrHash_num_nodes(hash) > TrHash_num_buckets(hash)) {
|
|
/* expand trie hash */
|
|
TrNode chain, next, *first_bucket, *new_bucket;
|
|
int seed;
|
|
first_bucket = TrHash_buckets(hash);
|
|
bucket = first_bucket + TrHash_num_buckets(hash);
|
|
TrHash_num_buckets(hash) *= 2;
|
|
new_hash_buckets(hash, TrHash_num_buckets(hash));
|
|
seed = TrHash_num_buckets(hash) - 1;
|
|
do {
|
|
if (*--bucket) {
|
|
chain = *bucket;
|
|
do {
|
|
new_bucket = TrHash_bucket(hash, HASH_TERM(TrNode_entry(chain), seed));
|
|
next = TrNode_next(chain);
|
|
TrNode_next(chain) = *new_bucket;
|
|
TrNode_previous(chain) = AS_TR_NODE_NEXT(bucket);
|
|
if (*new_bucket)
|
|
TrNode_previous(*new_bucket) = chain;
|
|
*new_bucket = chain;
|
|
chain = next;
|
|
} while (chain);
|
|
}
|
|
} while (bucket != first_bucket);
|
|
free_hash_buckets(first_bucket, TrHash_num_buckets(hash) / 2);
|
|
}
|
|
} else {
|
|
int count = 0;
|
|
do {
|
|
if (TrNode_entry(child) == t)
|
|
return child;
|
|
count++;
|
|
child = TrNode_next(child);
|
|
} while (child);
|
|
new_trie_node(child, t, parent, NULL, TrNode_child(parent), NULL);
|
|
TrNode_previous(TrNode_child(parent)) = child;
|
|
if (++count > MAX_NODES_PER_TRIE_LEVEL) {
|
|
/* alloc a new trie hash */
|
|
TrHash hash;
|
|
TrNode chain, next, *bucket;
|
|
new_trie_hash(hash, count, BASE_HASH_BUCKETS);
|
|
chain = child;
|
|
do {
|
|
bucket = TrHash_bucket(hash, HASH_TERM(TrNode_entry(chain), BASE_HASH_BUCKETS - 1));
|
|
next = TrNode_next(chain);
|
|
TrNode_next(chain) = *bucket;
|
|
TrNode_previous(chain) = AS_TR_NODE_NEXT(bucket);
|
|
if (*bucket)
|
|
TrNode_previous(*bucket) = chain;
|
|
*bucket = chain;
|
|
chain = next;
|
|
} while (chain);
|
|
TrNode_child(parent) = (TrNode) hash;
|
|
} else
|
|
TrNode_child(parent) = child;
|
|
}
|
|
return child;
|
|
}
|
|
|
|
|
|
static inline
|
|
TrNode trie_node_insert(TrNode parent, YAP_Term t, TrHash hash) {
|
|
TrNode child;
|
|
|
|
CURRENT_DEPTH++;
|
|
if (hash) {
|
|
/* is trie hash */
|
|
TrNode *bucket;
|
|
TrHash_num_nodes(hash)++;
|
|
bucket = TrHash_bucket(hash, HASH_TERM(t, TrHash_seed(hash)));
|
|
new_trie_node(child, t, parent, NULL, *bucket, AS_TR_NODE_NEXT(bucket));
|
|
if (*bucket)
|
|
TrNode_previous(*bucket) = child;
|
|
*bucket = child;
|
|
} else {
|
|
new_trie_node(child, t, parent, NULL, TrNode_child(parent), NULL);
|
|
if (TrNode_child(parent))
|
|
TrNode_previous(TrNode_child(parent)) = child;
|
|
TrNode_child(parent) = child;
|
|
}
|
|
return child;
|
|
}
|
|
|
|
|
|
static inline
|
|
TrNode trie_node_check(TrNode parent, YAP_Term t) {
|
|
TrNode child;
|
|
|
|
child = TrNode_child(parent);
|
|
if (IS_HASH_NODE(child)) {
|
|
TrHash hash;
|
|
TrNode *bucket;
|
|
hash = (TrHash) child;
|
|
bucket = TrHash_bucket(hash, HASH_TERM(t, TrHash_seed(hash)));
|
|
child = *bucket;
|
|
if (!child)
|
|
return NULL;
|
|
}
|
|
do {
|
|
if (TrNode_entry(child) == t)
|
|
return child;
|
|
child = TrNode_next(child);
|
|
} while (child);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------- */
|
|
/* API */
|
|
/* -------------------------- */
|
|
|
|
inline
|
|
TrEngine core_trie_init_module(void) {
|
|
static int init_once = 1;
|
|
TrEngine engine;
|
|
|
|
if (init_once) {
|
|
new_struct(AUXILIARY_TERM_STACK, YAP_Term, BASE_AUXILIARY_TERM_STACK_SIZE * sizeof(YAP_Term));
|
|
CURRENT_AUXILIARY_TERM_STACK_SIZE = BASE_AUXILIARY_TERM_STACK_SIZE;
|
|
CURRENT_TRIE_MODE = TRIE_MODE_STANDARD;
|
|
FunctorComma = YAP_MkFunctor(YAP_LookupAtom(","), 2);
|
|
init_once = 0;
|
|
}
|
|
new_trie_engine(engine);
|
|
return engine;
|
|
}
|
|
|
|
|
|
inline
|
|
TrNode core_trie_open(TrEngine engine) {
|
|
TrNode node;
|
|
|
|
CURRENT_TRIE_ENGINE = engine;
|
|
new_trie_node(node, 0, NULL, NULL, TrEngine_trie(engine), AS_TR_NODE_NEXT(&TrEngine_trie(engine)));
|
|
if (TrEngine_trie(engine))
|
|
TrNode_previous(TrEngine_trie(engine)) = node;
|
|
TrEngine_trie(engine) = node;
|
|
INCREMENT_TRIES(CURRENT_TRIE_ENGINE);
|
|
return node;
|
|
}
|
|
|
|
|
|
inline
|
|
void core_trie_close(TrEngine engine, TrNode node, void (*destruct_function)(TrNode)) {
|
|
CURRENT_TRIE_ENGINE = engine;
|
|
DATA_DESTRUCT_FUNCTION = destruct_function;
|
|
if (TrNode_child(node))
|
|
remove_child_nodes(TrNode_child(node));
|
|
if (TrNode_next(node)) {
|
|
TrNode_previous(TrNode_next(node)) = TrNode_previous(node);
|
|
TrNode_next(TrNode_previous(node)) = TrNode_next(node);
|
|
} else
|
|
TrNode_next(TrNode_previous(node)) = NULL;
|
|
free_trie_node(node);
|
|
DECREMENT_TRIES(CURRENT_TRIE_ENGINE);
|
|
return;
|
|
}
|
|
|
|
|
|
inline
|
|
void core_trie_close_all(TrEngine engine, void (*destruct_function)(TrNode)) {
|
|
while (TrEngine_trie(engine))
|
|
core_trie_close(engine, TrEngine_trie(engine), destruct_function);
|
|
return;
|
|
}
|
|
|
|
|
|
inline
|
|
void core_trie_set_mode(YAP_Int mode) {
|
|
CURRENT_TRIE_MODE = mode;
|
|
return;
|
|
}
|
|
|
|
|
|
inline
|
|
YAP_Int core_trie_get_mode(void) {
|
|
return CURRENT_TRIE_MODE;
|
|
}
|
|
|
|
|
|
inline
|
|
TrNode core_trie_put_entry(TrEngine engine, TrNode node, YAP_Term entry, YAP_Int *depth) {
|
|
CURRENT_TRIE_ENGINE = engine;
|
|
CURRENT_DEPTH = 0;
|
|
stack_args_base = stack_args = AUXILIARY_TERM_STACK;
|
|
stack_vars_base = stack_vars = AUXILIARY_TERM_STACK + CURRENT_AUXILIARY_TERM_STACK_SIZE - 1;
|
|
node = put_entry(node, entry);
|
|
if (!IS_LEAF_TRIE_NODE(node)) {
|
|
MARK_AS_LEAF_TRIE_NODE(node);
|
|
INCREMENT_ENTRIES(CURRENT_TRIE_ENGINE);
|
|
}
|
|
/* reset var terms */
|
|
while (STACK_NOT_EMPTY(stack_vars++, stack_vars_base)) {
|
|
POP_DOWN(stack_vars);
|
|
*((YAP_Term *)*stack_vars) = *stack_vars;
|
|
}
|
|
if (depth)
|
|
*depth = CURRENT_DEPTH;
|
|
return node;
|
|
}
|
|
|
|
|
|
inline
|
|
TrNode core_trie_check_entry(TrNode node, YAP_Term entry) {
|
|
if (!TrNode_child(node))
|
|
return NULL;
|
|
stack_args_base = stack_args = AUXILIARY_TERM_STACK;
|
|
stack_vars_base = stack_vars = AUXILIARY_TERM_STACK + CURRENT_AUXILIARY_TERM_STACK_SIZE - 1;
|
|
node = check_entry(node, entry);
|
|
/* reset var terms */
|
|
while (STACK_NOT_EMPTY(stack_vars++, stack_vars_base)) {
|
|
POP_DOWN(stack_vars);
|
|
*((YAP_Term *)*stack_vars) = *stack_vars;
|
|
}
|
|
return node;
|
|
}
|
|
|
|
|
|
inline
|
|
YAP_Term core_trie_get_entry(TrNode node) {
|
|
CURRENT_INDEX = -1;
|
|
stack_vars_base = stack_vars = AUXILIARY_TERM_STACK;
|
|
stack_args_base = stack_args = AUXILIARY_TERM_STACK + CURRENT_AUXILIARY_TERM_STACK_SIZE - 1;
|
|
return get_entry(node, stack_args, &node);
|
|
}
|
|
|
|
|
|
inline
|
|
void core_trie_remove_entry(TrEngine engine, TrNode node, void (*destruct_function)(TrNode)) {
|
|
CURRENT_TRIE_ENGINE = engine;
|
|
DATA_DESTRUCT_FUNCTION = destruct_function;
|
|
if (DATA_DESTRUCT_FUNCTION)
|
|
(*DATA_DESTRUCT_FUNCTION)(node);
|
|
DECREMENT_ENTRIES(CURRENT_TRIE_ENGINE);
|
|
remove_entry(node);
|
|
return;
|
|
}
|
|
|
|
|
|
inline
|
|
void core_trie_remove_subtree(TrEngine engine, TrNode node, void (*destruct_function)(TrNode)) {
|
|
TrNode parent;
|
|
|
|
CURRENT_TRIE_ENGINE = engine;
|
|
DATA_DESTRUCT_FUNCTION = destruct_function;
|
|
parent = TrNode_parent(node);
|
|
remove_child_nodes(TrNode_child(parent));
|
|
remove_entry(parent);
|
|
return;
|
|
}
|
|
|
|
|
|
inline
|
|
void core_trie_add(TrNode node_dest, TrNode node_source, void (*add_function)(TrNode, TrNode)) {
|
|
DATA_ADD_FUNCTION = add_function;
|
|
if (TrNode_child(node_dest) && TrNode_child(node_source))
|
|
traverse_and_add(node_dest, node_source);
|
|
return;
|
|
}
|
|
|
|
|
|
inline
|
|
void core_trie_join(TrEngine engine, TrNode node_dest, TrNode node_source, void (*add_function)(TrNode, TrNode), void (*copy_function)(TrNode, TrNode)) {
|
|
CURRENT_TRIE_ENGINE = engine;
|
|
DATA_ADD_FUNCTION = add_function;
|
|
DATA_COPY_FUNCTION = copy_function;
|
|
if (TrNode_child(node_dest)) {
|
|
if (TrNode_child(node_source))
|
|
traverse_and_join(node_dest, node_source);
|
|
} else if (TrNode_child(node_source))
|
|
TrNode_child(node_dest) = copy_child_nodes(node_dest, TrNode_child(node_source));
|
|
return;
|
|
}
|
|
|
|
|
|
inline
|
|
void core_trie_intersect(TrEngine engine, TrNode node_dest, TrNode node_source, void (*add_function)(TrNode, TrNode), void (*destruct_function)(TrNode)) {
|
|
CURRENT_TRIE_ENGINE = engine;
|
|
DATA_ADD_FUNCTION = add_function;
|
|
DATA_DESTRUCT_FUNCTION = destruct_function;
|
|
if (TrNode_child(node_dest)) {
|
|
if (TrNode_child(node_source))
|
|
traverse_and_intersect(node_dest, node_source);
|
|
else {
|
|
remove_child_nodes(TrNode_child(node_dest));
|
|
TrNode_child(node_dest) = NULL;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
inline
|
|
YAP_Int core_trie_count_join(TrNode node1, TrNode node2) {
|
|
YAP_Int count = 0;
|
|
|
|
if (TrNode_child(node1)) {
|
|
count += traverse_and_count_entries(TrNode_child(node1));
|
|
if (TrNode_child(node2)) {
|
|
count += traverse_and_count_entries(TrNode_child(node2));
|
|
count -= traverse_and_count_common_entries(node1, node2);
|
|
}
|
|
} else if (TrNode_child(node2))
|
|
count += traverse_and_count_entries(TrNode_child(node2));
|
|
return count;
|
|
}
|
|
|
|
|
|
inline
|
|
YAP_Int core_trie_count_intersect(TrNode node1, TrNode node2) {
|
|
YAP_Int count = 0;
|
|
|
|
if (TrNode_child(node1))
|
|
if (TrNode_child(node2))
|
|
count = traverse_and_count_common_entries(node1, node2);
|
|
return count;
|
|
}
|
|
|
|
|
|
inline
|
|
void core_trie_save(TrNode node, FILE *file, void (*save_function)(TrNode, FILE *)) {
|
|
CURRENT_INDEX = -1;
|
|
DATA_SAVE_FUNCTION = save_function;
|
|
if (TrNode_child(node)) {
|
|
fprintf(file, "BEGIN_TRIE_v2 ");
|
|
traverse_and_save(TrNode_child(node), file, 0);
|
|
fprintf(file, "END_TRIE_v2");
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
inline
|
|
TrNode core_trie_load(TrEngine engine, FILE *file, void (*load_function)(TrNode, YAP_Int, FILE *)) {
|
|
TrNode node;
|
|
char version[15];
|
|
fpos_t curpos;
|
|
|
|
fscanf(file, "%14s", version);
|
|
if (fgetpos(file, &curpos) ) return NULL;
|
|
|
|
if (!strcmp(version, "BEGIN_TRIE_v2")) {
|
|
fseek(file, -11, SEEK_END);
|
|
fscanf(file, "%s", version);
|
|
if (strcmp(version, "END_TRIE_v2")) {
|
|
fprintf(stderr, "******************************************\n");
|
|
fprintf(stderr, " Tries core module: trie file corrupted\n");
|
|
fprintf(stderr, "******************************************\n");
|
|
return NULL;
|
|
}
|
|
if (fsetpos(file, &curpos) ) return NULL;
|
|
CURRENT_LOAD_VERSION = 2;
|
|
} else if (!strcmp(version, "BEGIN_TRIE")) {
|
|
fseek(file, -8, SEEK_END);
|
|
fscanf(file, "%s", version);
|
|
if (strcmp(version, "END_TRIE")) {
|
|
fprintf(stderr, "******************************************\n");
|
|
fprintf(stderr, " Tries core module: trie file corrupted\n");
|
|
fprintf(stderr, "******************************************\n");
|
|
return NULL;
|
|
}
|
|
if (fsetpos(file, &curpos) ) return NULL;
|
|
CURRENT_LOAD_VERSION = 1;
|
|
} else {
|
|
fprintf(stderr, "****************************************\n");
|
|
fprintf(stderr, " Tries core module: invalid trie file\n");
|
|
fprintf(stderr, "****************************************\n");
|
|
return NULL;
|
|
}
|
|
CURRENT_TRIE_ENGINE = engine;
|
|
CURRENT_INDEX = -1;
|
|
CURRENT_DEPTH = 0;
|
|
DATA_LOAD_FUNCTION = load_function;
|
|
node = core_trie_open(engine);
|
|
traverse_and_load(node, file);
|
|
return node;
|
|
}
|
|
|
|
|
|
inline
|
|
void core_trie_stats(TrEngine engine, YAP_Int *memory, YAP_Int *tries, YAP_Int *entries, YAP_Int *nodes) {
|
|
*memory = TrEngine_memory(engine);
|
|
*tries = TrEngine_tries(engine);
|
|
*entries = TrEngine_entries(engine);
|
|
*nodes = TrEngine_nodes(engine);
|
|
return;
|
|
}
|
|
|
|
|
|
inline
|
|
void core_trie_max_stats(TrEngine engine, YAP_Int *memory, YAP_Int *tries, YAP_Int *entries, YAP_Int *nodes) {
|
|
*memory = TrEngine_memory_max(engine);
|
|
*tries = TrEngine_tries_max(engine);
|
|
*entries = TrEngine_entries_max(engine);
|
|
*nodes = TrEngine_nodes_max(engine);
|
|
return;
|
|
}
|
|
|
|
|
|
inline
|
|
void core_trie_usage(TrNode node, YAP_Int *entries, YAP_Int *nodes, YAP_Int *virtual_nodes) {
|
|
USAGE_ENTRIES = 0;
|
|
USAGE_NODES = 0;
|
|
USAGE_VIRTUAL_NODES = 0;
|
|
if (TrNode_child(node))
|
|
traverse_and_get_usage(TrNode_child(node), 0);
|
|
*entries = USAGE_ENTRIES;
|
|
*nodes = USAGE_NODES;
|
|
*virtual_nodes = USAGE_VIRTUAL_NODES;
|
|
return;
|
|
}
|
|
|
|
|
|
inline
|
|
void core_trie_print(TrNode node, void (*print_function)(TrNode)) {
|
|
DATA_PRINT_FUNCTION = print_function;
|
|
if (TrNode_child(node)) {
|
|
YAP_Int arity[100];
|
|
char str[10000];
|
|
arity[0] = 0;
|
|
traverse_and_print(TrNode_child(node), arity, str, 0, TRIE_PRINT_NORMAL);
|
|
} else
|
|
fprintf(stdout, "(empty)\n");
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* -------------------------- */
|
|
/* Local Procedures */
|
|
/* -------------------------- */
|
|
|
|
static
|
|
TrNode put_entry(TrNode node, YAP_Term entry) {
|
|
YAP_Term t = YAP_Deref(entry);
|
|
if (YAP_IsVarTerm(t)) {
|
|
if (IsTrieVar(t, stack_vars, stack_vars_base)) {
|
|
node = trie_node_check_insert(node, MkTrieVar((stack_vars_base - 1 - (YAP_Term *)t) / 2));
|
|
} else {
|
|
node = trie_node_check_insert(node, MkTrieVar((stack_vars_base - stack_vars) / 2));
|
|
PUSH_UP(stack_vars, t, stack_args);
|
|
*((YAP_Term *)t) = (YAP_Term)stack_vars;
|
|
PUSH_UP(stack_vars, stack_vars, stack_args);
|
|
}
|
|
} else if (YAP_IsAtomTerm(t)) {
|
|
node = trie_node_check_insert(node, t);
|
|
} else if (YAP_IsIntTerm(t)) {
|
|
node = trie_node_check_insert(node, t);
|
|
} else if (YAP_IsFloatTerm(t)) {
|
|
volatile double f;
|
|
volatile YAP_Term *p;
|
|
f = YAP_FloatOfTerm(t);
|
|
p = (YAP_Term *)((void *) &f); /* to avoid gcc warning */
|
|
node = trie_node_check_insert(node, FloatInitTag);
|
|
node = trie_node_check_insert(node, *p);
|
|
#ifdef TAG_LOW_BITS_32
|
|
node = trie_node_check_insert(node, *(p + 1));
|
|
#endif /* TAG_LOW_BITS_32 */
|
|
node = trie_node_check_insert(node, FloatEndTag);
|
|
} else if (YAP_IsPairTerm(t)) {
|
|
node = trie_node_check_insert(node, PairInitTag);
|
|
if (CURRENT_TRIE_MODE == TRIE_MODE_STANDARD) {
|
|
do {
|
|
node = put_entry(node, YAP_HeadOfTerm(t));
|
|
t = YAP_Deref(YAP_TailOfTerm(t));
|
|
} while (YAP_IsPairTerm(t));
|
|
} else { /* TRIE_MODE_REVERSE */
|
|
YAP_Term *stack_list = stack_args;
|
|
do {
|
|
PUSH_DOWN(stack_args, YAP_HeadOfTerm(t), stack_vars);
|
|
t = YAP_Deref(YAP_TailOfTerm(t));
|
|
} while (YAP_IsPairTerm(t));
|
|
while (STACK_NOT_EMPTY(stack_args, stack_list))
|
|
node = put_entry(node, POP_UP(stack_args));
|
|
}
|
|
node = trie_node_check_insert(node, PairEndTag);
|
|
} else if (YAP_IsApplTerm(t)) {
|
|
YAP_Functor f = YAP_FunctorOfTerm(t);
|
|
if (f == FunctorComma) {
|
|
node = trie_node_check_insert(node, CommaInitTag);
|
|
do {
|
|
node = put_entry(node, YAP_ArgOfTerm(1, t));
|
|
t = YAP_Deref(YAP_ArgOfTerm(2, t));
|
|
} while (YAP_IsApplTerm(t) && YAP_FunctorOfTerm(t) == FunctorComma);
|
|
node = put_entry(node, t);
|
|
node = trie_node_check_insert(node, CommaEndTag);
|
|
} else {
|
|
int i;
|
|
node = trie_node_check_insert(node, ApplTag | ((YAP_Term) f));
|
|
for (i = 1; i <= YAP_ArityOfFunctor(f); i++)
|
|
node = put_entry(node, YAP_ArgOfTerm(i, t));
|
|
}
|
|
} else {
|
|
fprintf(stderr, "***************************************\n");
|
|
fprintf(stderr, " Tries core module: unknown type tag\n");
|
|
fprintf(stderr, "***************************************\n");
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
|
|
static
|
|
TrNode check_entry(TrNode node, YAP_Term entry) {
|
|
YAP_Term t = YAP_Deref(entry);
|
|
if (YAP_IsVarTerm(t)) {
|
|
if (IsTrieVar(t, stack_vars, stack_vars_base)) {
|
|
if (!(node = trie_node_check(node, MkTrieVar((stack_vars_base - 1 - (YAP_Term *)t) / 2))))
|
|
return NULL;
|
|
} else {
|
|
if (!(node = trie_node_check(node, MkTrieVar((stack_vars_base - stack_vars) / 2))))
|
|
return NULL;
|
|
PUSH_UP(stack_vars, t, stack_args);
|
|
*((YAP_Term *)t) = (YAP_Term)stack_vars;
|
|
PUSH_UP(stack_vars, stack_vars, stack_args);
|
|
}
|
|
} else if (YAP_IsAtomTerm(t)) {
|
|
if (!(node = trie_node_check(node, t)))
|
|
return NULL;
|
|
} else if (YAP_IsIntTerm(t)) {
|
|
if (!(node = trie_node_check(node, t)))
|
|
return NULL;
|
|
} else if (YAP_IsFloatTerm(t)) {
|
|
volatile double f;
|
|
volatile YAP_Term *p;
|
|
f = YAP_FloatOfTerm(t);
|
|
p = (YAP_Term *)((void *) &f); /* to avoid gcc warning */
|
|
if (!(node = trie_node_check(node, FloatInitTag)))
|
|
return NULL;
|
|
if (!(node = trie_node_check(node, *p)))
|
|
return NULL;
|
|
#ifdef TAG_LOW_BITS_32
|
|
if (!(node = trie_node_check(node, *(p + 1))))
|
|
return NULL;
|
|
#endif /* TAG_LOW_BITS_32 */
|
|
if (!(node = trie_node_check(node, FloatEndTag)))
|
|
return NULL;
|
|
} else if (YAP_IsPairTerm(t)) {
|
|
if (!(node = trie_node_check(node, PairInitTag)))
|
|
return NULL;
|
|
if (CURRENT_TRIE_MODE == TRIE_MODE_STANDARD) {
|
|
do {
|
|
if (!(node = check_entry(node, YAP_HeadOfTerm(t))))
|
|
return NULL;
|
|
t = YAP_Deref(YAP_TailOfTerm(t));
|
|
} while (YAP_IsPairTerm(t));
|
|
} else { /* TRIE_MODE_REVERSE */
|
|
YAP_Term *stack_list = stack_args;
|
|
do {
|
|
PUSH_DOWN(stack_args, YAP_HeadOfTerm(t), stack_vars);
|
|
t = YAP_Deref(YAP_TailOfTerm(t));
|
|
} while (YAP_IsPairTerm(t));
|
|
while (STACK_NOT_EMPTY(stack_args, stack_list))
|
|
if (!(node = check_entry(node, POP_UP(stack_args))))
|
|
return NULL;
|
|
}
|
|
if (!(node = trie_node_check(node, PairEndTag)))
|
|
return NULL;
|
|
} else if (YAP_IsApplTerm(t)) {
|
|
YAP_Functor f = YAP_FunctorOfTerm(t);
|
|
if (f == FunctorComma) {
|
|
if (!(node = trie_node_check(node, CommaInitTag)))
|
|
return NULL;
|
|
do {
|
|
if (!(node = check_entry(node, YAP_ArgOfTerm(1, t))))
|
|
return NULL;
|
|
t = YAP_Deref(YAP_ArgOfTerm(2, t));
|
|
} while (YAP_IsApplTerm(t) && YAP_FunctorOfTerm(t) == FunctorComma);
|
|
if (!(node = check_entry(node, t)))
|
|
return NULL;
|
|
if (!(node = trie_node_check(node, CommaEndTag)))
|
|
return NULL;
|
|
} else {
|
|
int i;
|
|
if (!(node = trie_node_check(node, ApplTag | ((YAP_Term) f))))
|
|
return NULL;
|
|
for (i = 1; i <= YAP_ArityOfFunctor(f); i++)
|
|
if (!(node = check_entry(node, YAP_ArgOfTerm(i, t))))
|
|
return NULL;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "***************************************\n");
|
|
fprintf(stderr, " Tries core module: unknown type tag\n");
|
|
fprintf(stderr, "***************************************\n");
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
|
|
static
|
|
YAP_Term get_entry(TrNode node, YAP_Term *stack_mark, TrNode *cur_node) {
|
|
YAP_Term t = (YAP_Term) &t;
|
|
while (TrNode_parent(node)) {
|
|
t = TrNode_entry(node);
|
|
if (YAP_IsVarTerm(t)) {
|
|
int index = TrieVarIndex(t);
|
|
if (index > CURRENT_INDEX) {
|
|
int i;
|
|
stack_vars = &stack_vars_base[index + 1];
|
|
if (stack_vars > stack_args + 1) {
|
|
fprintf(stderr, "**************************************\n");
|
|
fprintf(stderr, " Tries core module: term stack full\n");
|
|
fprintf(stderr, "**************************************\n");
|
|
}
|
|
for (i = index; i > CURRENT_INDEX; i--)
|
|
stack_vars_base[i] = 0;
|
|
CURRENT_INDEX = index;
|
|
}
|
|
if (stack_vars_base[index]) {
|
|
t = stack_vars_base[index];
|
|
} else {
|
|
t = YAP_MkVarTerm();
|
|
stack_vars_base[index] = t;
|
|
}
|
|
PUSH_UP(stack_args, t, stack_vars);
|
|
} else if (YAP_IsAtomTerm(t)) {
|
|
PUSH_UP(stack_args, t, stack_vars);
|
|
} else if (YAP_IsIntTerm(t)) {
|
|
PUSH_UP(stack_args, t, stack_vars);
|
|
} else if (YAP_IsPairTerm(t)) {
|
|
if (t == PairEndTag) {
|
|
if (CURRENT_TRIE_MODE == TRIE_MODE_STANDARD) {
|
|
t = YAP_MkAtomTerm(YAP_LookupAtom("[]"));
|
|
PUSH_UP(stack_args, t, stack_vars);
|
|
node = TrNode_parent(node);
|
|
t = get_entry(node, &stack_args[1], &node);
|
|
} else { /* TRIE_MODE_REVERSE */
|
|
node = TrNode_parent(node);
|
|
t = get_entry(node, stack_args, &node);
|
|
}
|
|
PUSH_UP(stack_args, t, stack_vars);
|
|
} else if (t == PairInitTag) {
|
|
YAP_Term t2;
|
|
if (CURRENT_TRIE_MODE == TRIE_MODE_STANDARD) {
|
|
YAP_Term *stack_aux = stack_mark;
|
|
t = *stack_aux--;
|
|
while (STACK_NOT_EMPTY(stack_aux, stack_args)) {
|
|
t2 = *stack_aux--;
|
|
t = YAP_MkPairTerm(t2, t);
|
|
}
|
|
stack_args = stack_mark;
|
|
} else { /* TRIE_MODE_REVERSE */
|
|
t = YAP_MkAtomTerm(YAP_LookupAtom("[]"));
|
|
while (STACK_NOT_EMPTY(stack_args, stack_mark)) {
|
|
t2 = POP_DOWN(stack_args);
|
|
t = YAP_MkPairTerm(t2, t);
|
|
}
|
|
}
|
|
*cur_node = node;
|
|
return t;
|
|
} else if (t == CommaEndTag) {
|
|
node = TrNode_parent(node);
|
|
t = get_entry(node, stack_args, &node);
|
|
PUSH_UP(stack_args, t, stack_vars);
|
|
} else if (t == CommaInitTag) {
|
|
YAP_Term *stack_aux = stack_mark;
|
|
stack_aux--;
|
|
while (STACK_NOT_EMPTY(stack_aux, stack_args)) {
|
|
t = YAP_MkApplTerm(FunctorComma, 2, stack_aux);
|
|
*stack_aux = t;
|
|
stack_aux--;
|
|
}
|
|
stack_args = stack_mark;
|
|
*cur_node = node;
|
|
return t;
|
|
} else if (t == FloatEndTag) {
|
|
volatile double f;
|
|
volatile YAP_Term *p;
|
|
p = (YAP_Term *)((void *) &f); /* to avoid gcc warning */
|
|
#ifdef TAG_LOW_BITS_32
|
|
node = TrNode_parent(node);
|
|
*(p + 1) = TrNode_entry(node);
|
|
#endif /* TAG_LOW_BITS_32 */
|
|
node = TrNode_parent(node);
|
|
*p = TrNode_entry(node);
|
|
node = TrNode_parent(node); /* ignore FloatInitTag */
|
|
t = YAP_MkFloatTerm(f);
|
|
PUSH_UP(stack_args, t, stack_vars);
|
|
} else if (t == FloatInitTag) {
|
|
}
|
|
} else if (ApplTag & t) {
|
|
YAP_Functor f = (YAP_Functor)(~ApplTag & t);
|
|
int arity = YAP_ArityOfFunctor(f);
|
|
t = YAP_MkApplTerm(f, arity, &stack_args[1]);
|
|
stack_args += arity;
|
|
PUSH_UP(stack_args, t, stack_vars);
|
|
} else {
|
|
fprintf(stderr, "***************************************\n");
|
|
fprintf(stderr, " Tries core module: unknown type tag\n");
|
|
fprintf(stderr, "***************************************\n");
|
|
}
|
|
node = TrNode_parent(node);
|
|
}
|
|
*cur_node = node;
|
|
return t;
|
|
}
|
|
|
|
|
|
static
|
|
void remove_entry(TrNode node) {
|
|
TrNode parent = TrNode_parent(node);
|
|
while (parent) {
|
|
if (TrNode_previous(node)) {
|
|
if (IS_HASH_NODE(TrNode_child(parent))) {
|
|
TrHash hash = (TrHash) TrNode_child(parent);
|
|
TrHash_num_nodes(hash)--;
|
|
if (TrHash_num_nodes(hash)) {
|
|
if (TrNode_next(node)) {
|
|
TrNode_next(TrNode_previous(node)) = TrNode_next(node);
|
|
TrNode_previous(TrNode_next(node)) = TrNode_previous(node);
|
|
} else {
|
|
TrNode_next(TrNode_previous(node)) = NULL;
|
|
}
|
|
free_trie_node(node);
|
|
return;
|
|
}
|
|
free_hash_buckets(TrHash_buckets(hash), TrHash_num_buckets(hash));
|
|
free_trie_hash(hash);
|
|
} else {
|
|
if (TrNode_next(node)) {
|
|
TrNode_next(TrNode_previous(node)) = TrNode_next(node);
|
|
TrNode_previous(TrNode_next(node)) = TrNode_previous(node);
|
|
} else {
|
|
TrNode_next(TrNode_previous(node)) = NULL;
|
|
}
|
|
free_trie_node(node);
|
|
return;
|
|
}
|
|
} else if (TrNode_next(node)) {
|
|
TrNode_child(parent) = TrNode_next(node);
|
|
TrNode_previous(TrNode_next(node)) = NULL;
|
|
free_trie_node(node);
|
|
return;
|
|
}
|
|
free_trie_node(node);
|
|
node = parent;
|
|
parent = TrNode_parent(node);
|
|
}
|
|
TrNode_child(node) = NULL;
|
|
return;
|
|
}
|
|
|
|
|
|
static
|
|
void remove_child_nodes(TrNode node) {
|
|
if (IS_HASH_NODE(node)) {
|
|
TrNode *first_bucket, *bucket;
|
|
TrHash hash = (TrHash) node;
|
|
first_bucket = TrHash_buckets(hash);
|
|
bucket = first_bucket + TrHash_num_buckets(hash);
|
|
do {
|
|
if (*--bucket)
|
|
remove_child_nodes(*bucket);
|
|
} while (bucket != first_bucket);
|
|
free_hash_buckets(first_bucket, TrHash_num_buckets(hash));
|
|
free_trie_hash(hash);
|
|
return;
|
|
}
|
|
if (TrNode_next(node))
|
|
remove_child_nodes(TrNode_next(node));
|
|
if (!IS_LEAF_TRIE_NODE(node))
|
|
remove_child_nodes(TrNode_child(node));
|
|
else {
|
|
if (DATA_DESTRUCT_FUNCTION)
|
|
(*DATA_DESTRUCT_FUNCTION)(node);
|
|
DECREMENT_ENTRIES(CURRENT_TRIE_ENGINE);
|
|
}
|
|
free_trie_node(node);
|
|
return;
|
|
}
|
|
|
|
|
|
static
|
|
TrNode copy_child_nodes(TrNode parent_dest, TrNode child_source) {
|
|
TrNode child_dest, next_dest;
|
|
|
|
if (IS_HASH_NODE(child_source)) {
|
|
TrNode *bucket_dest, *first_bucket_source, *bucket_source;
|
|
TrHash hash_dest, hash_source;
|
|
hash_source = (TrHash) child_source;
|
|
first_bucket_source = TrHash_buckets(hash_source);
|
|
bucket_source = first_bucket_source + TrHash_num_buckets(hash_source);
|
|
new_trie_hash(hash_dest, TrHash_num_nodes(hash_source), TrHash_num_buckets(hash_source));
|
|
bucket_dest = TrHash_buckets(hash_dest) + TrHash_num_buckets(hash_dest);
|
|
do {
|
|
bucket_dest--;
|
|
if (*--bucket_source) {
|
|
*bucket_dest = copy_child_nodes(parent_dest, *bucket_source);
|
|
TrNode_previous(*bucket_dest) = AS_TR_NODE_NEXT(bucket_dest);
|
|
} else
|
|
*bucket_dest = NULL;
|
|
} while (bucket_source != first_bucket_source);
|
|
return (TrNode) hash_dest;
|
|
}
|
|
|
|
if (TrNode_next(child_source))
|
|
next_dest = copy_child_nodes(parent_dest, TrNode_next(child_source));
|
|
else
|
|
next_dest = NULL;
|
|
new_trie_node(child_dest, TrNode_entry(child_source), parent_dest, NULL, next_dest, NULL);
|
|
if (next_dest)
|
|
TrNode_previous(next_dest) = child_dest;
|
|
if (IS_LEAF_TRIE_NODE(child_source)) {
|
|
MARK_AS_LEAF_TRIE_NODE(child_dest);
|
|
INCREMENT_ENTRIES(CURRENT_TRIE_ENGINE);
|
|
if (DATA_COPY_FUNCTION)
|
|
(*DATA_COPY_FUNCTION)(child_dest, child_source);
|
|
} else
|
|
TrNode_child(child_dest) = copy_child_nodes(child_dest, TrNode_child(child_source));
|
|
return child_dest;
|
|
}
|
|
|
|
|
|
static
|
|
void traverse_and_add(TrNode parent_dest, TrNode parent_source) {
|
|
TrNode child_dest, child_source;
|
|
|
|
/* parent_source is not a leaf node */
|
|
child_source = TrNode_child(parent_source);
|
|
if (IS_HASH_NODE(child_source)) {
|
|
TrNode *first_bucket_source, *bucket_source;
|
|
TrHash hash_source;
|
|
hash_source = (TrHash) child_source;
|
|
first_bucket_source = TrHash_buckets(hash_source);
|
|
bucket_source = first_bucket_source + TrHash_num_buckets(hash_source);
|
|
do {
|
|
child_source = *--bucket_source;
|
|
while (child_source) {
|
|
/* parent_dest is not a leaf node */
|
|
child_dest = trie_node_check(parent_dest, TrNode_entry(child_source));
|
|
if (child_dest) {
|
|
if (IS_LEAF_TRIE_NODE(child_dest)) {
|
|
/* child_source is a leaf node */
|
|
if (DATA_ADD_FUNCTION)
|
|
(*DATA_ADD_FUNCTION)(child_dest, child_source);
|
|
} else
|
|
/* child_dest and child_source are not leaf nodes */
|
|
traverse_and_add(child_dest, child_source);
|
|
}
|
|
child_source = TrNode_next(child_source);
|
|
}
|
|
} while (bucket_source != first_bucket_source);
|
|
return;
|
|
}
|
|
while (child_source) {
|
|
/* parent_dest is not a leaf node */
|
|
child_dest = trie_node_check(parent_dest, TrNode_entry(child_source));
|
|
if (child_dest) {
|
|
if (IS_LEAF_TRIE_NODE(child_dest)) {
|
|
/* child_source is a leaf node */
|
|
if (DATA_ADD_FUNCTION)
|
|
(*DATA_ADD_FUNCTION)(child_dest, child_source);
|
|
} else
|
|
/* child_dest and child_source are not leaf nodes */
|
|
traverse_and_add(child_dest, child_source);
|
|
}
|
|
child_source = TrNode_next(child_source);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
static
|
|
void traverse_and_join(TrNode parent_dest, TrNode parent_source) {
|
|
TrNode child_dest, child_source;
|
|
|
|
/* parent_source is not a leaf node */
|
|
child_source = TrNode_child(parent_source);
|
|
if (IS_HASH_NODE(child_source)) {
|
|
TrNode *first_bucket_source, *bucket_source;
|
|
TrHash hash_source;
|
|
hash_source = (TrHash) child_source;
|
|
first_bucket_source = TrHash_buckets(hash_source);
|
|
bucket_source = first_bucket_source + TrHash_num_buckets(hash_source);
|
|
do {
|
|
child_source = *--bucket_source;
|
|
while (child_source) {
|
|
/* parent_dest is not a leaf node */
|
|
child_dest = trie_node_check(parent_dest, TrNode_entry(child_source));
|
|
if (child_dest) {
|
|
if (IS_LEAF_TRIE_NODE(child_dest)) {
|
|
/* child_source is a leaf node */
|
|
if (DATA_ADD_FUNCTION)
|
|
(*DATA_ADD_FUNCTION)(child_dest, child_source);
|
|
} else
|
|
/* child_dest and child_source are not leaf nodes */
|
|
traverse_and_join(child_dest, child_source);
|
|
} else {
|
|
child_dest = trie_node_check_insert(parent_dest, TrNode_entry(child_source));
|
|
if (IS_LEAF_TRIE_NODE(child_source)) {
|
|
MARK_AS_LEAF_TRIE_NODE(child_dest);
|
|
INCREMENT_ENTRIES(CURRENT_TRIE_ENGINE);
|
|
if (DATA_COPY_FUNCTION)
|
|
(*DATA_COPY_FUNCTION)(child_dest, child_source);
|
|
} else
|
|
TrNode_child(child_dest) = copy_child_nodes(child_dest, TrNode_child(child_source));
|
|
}
|
|
child_source = TrNode_next(child_source);
|
|
}
|
|
} while (bucket_source != first_bucket_source);
|
|
return;
|
|
}
|
|
while (child_source) {
|
|
/* parent_dest is not a leaf node */
|
|
child_dest = trie_node_check(parent_dest, TrNode_entry(child_source));
|
|
if (child_dest) {
|
|
if (IS_LEAF_TRIE_NODE(child_dest)) {
|
|
/* child_source is a leaf node */
|
|
if (DATA_ADD_FUNCTION)
|
|
(*DATA_ADD_FUNCTION)(child_dest, child_source);
|
|
} else
|
|
/* child_dest and child_source are not leaf nodes */
|
|
traverse_and_join(child_dest, child_source);
|
|
} else {
|
|
child_dest = trie_node_check_insert(parent_dest, TrNode_entry(child_source));
|
|
if (IS_LEAF_TRIE_NODE(child_source)) {
|
|
MARK_AS_LEAF_TRIE_NODE(child_dest);
|
|
INCREMENT_ENTRIES(CURRENT_TRIE_ENGINE);
|
|
if (DATA_COPY_FUNCTION)
|
|
(*DATA_COPY_FUNCTION)(child_dest, child_source);
|
|
} else
|
|
TrNode_child(child_dest) = copy_child_nodes(child_dest, TrNode_child(child_source));
|
|
}
|
|
child_source = TrNode_next(child_source);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
static
|
|
void traverse_and_intersect(TrNode parent_dest, TrNode parent_source) {
|
|
TrNode child_dest, child_source, child_next;
|
|
|
|
/* parent_dest is not a leaf node */
|
|
child_dest = TrNode_child(parent_dest);
|
|
if (IS_HASH_NODE(child_dest)) {
|
|
TrNode *first_bucket_dest, *bucket_dest;
|
|
TrHash hash_dest;
|
|
hash_dest = (TrHash) child_dest;
|
|
first_bucket_dest = TrHash_buckets(hash_dest);
|
|
bucket_dest = first_bucket_dest + TrHash_num_buckets(hash_dest);
|
|
do {
|
|
child_dest = *--bucket_dest;
|
|
while (child_dest) {
|
|
child_next = TrNode_next(child_dest);
|
|
/* parent_source is not a leaf node */
|
|
child_source = trie_node_check(parent_source, TrNode_entry(child_dest));
|
|
if (child_source) {
|
|
if (IS_LEAF_TRIE_NODE(child_dest)) {
|
|
/* child_source is a leaf node */
|
|
if (DATA_ADD_FUNCTION)
|
|
(*DATA_ADD_FUNCTION)(child_dest, child_source);
|
|
} else
|
|
/* child_dest and child_source are not leaf nodes */
|
|
traverse_and_intersect(child_dest, child_source);
|
|
} else {
|
|
if (IS_LEAF_TRIE_NODE(child_dest)) {
|
|
if (DATA_DESTRUCT_FUNCTION)
|
|
(*DATA_DESTRUCT_FUNCTION)(child_dest);
|
|
DECREMENT_ENTRIES(CURRENT_TRIE_ENGINE);
|
|
} else
|
|
remove_child_nodes(TrNode_child(child_dest));
|
|
remove_entry(child_dest);
|
|
}
|
|
child_dest = child_next;
|
|
}
|
|
} while (bucket_dest != first_bucket_dest);
|
|
return;
|
|
}
|
|
while (child_dest) {
|
|
child_next = TrNode_next(child_dest);
|
|
/* parent_source is not a leaf node */
|
|
child_source = trie_node_check(parent_source, TrNode_entry(child_dest));
|
|
if (child_source) {
|
|
if (IS_LEAF_TRIE_NODE(child_dest)) {
|
|
/* child_source is a leaf node */
|
|
if (DATA_ADD_FUNCTION)
|
|
(*DATA_ADD_FUNCTION)(child_dest, child_source);
|
|
} else
|
|
/* child_dest and child_source are not leaf nodes */
|
|
traverse_and_intersect(child_dest, child_source);
|
|
} else {
|
|
if (IS_LEAF_TRIE_NODE(child_dest)) {
|
|
if (DATA_DESTRUCT_FUNCTION)
|
|
(*DATA_DESTRUCT_FUNCTION)(child_dest);
|
|
DECREMENT_ENTRIES(CURRENT_TRIE_ENGINE);
|
|
} else
|
|
remove_child_nodes(TrNode_child(child_dest));
|
|
remove_entry(child_dest);
|
|
}
|
|
child_dest = child_next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
static
|
|
YAP_Int traverse_and_count_common_entries(TrNode parent1, TrNode parent2) {
|
|
TrNode child1, child2;
|
|
YAP_Int count = 0;
|
|
|
|
/* parent1 is not a leaf node */
|
|
child1 = TrNode_child(parent1);
|
|
if (IS_HASH_NODE(child1)) {
|
|
TrNode *first_bucket, *bucket;
|
|
TrHash hash;
|
|
hash = (TrHash) child1;
|
|
first_bucket = TrHash_buckets(hash);
|
|
bucket = first_bucket + TrHash_num_buckets(hash);
|
|
do {
|
|
child1 = *--bucket;
|
|
while (child1) {
|
|
/* parent2 is not a leaf node */
|
|
child2 = trie_node_check(parent2, TrNode_entry(child1));
|
|
if (child2) {
|
|
if (IS_LEAF_TRIE_NODE(child1))
|
|
/* child2 is a leaf node */
|
|
count++;
|
|
else
|
|
/* child1 and child2 are not leaf nodes */
|
|
count += traverse_and_count_common_entries(child1, child2);
|
|
}
|
|
child1 = TrNode_next(child1);
|
|
}
|
|
} while (bucket != first_bucket);
|
|
return count;
|
|
}
|
|
while (child1) {
|
|
/* parent2 is not a leaf node */
|
|
child2 = trie_node_check(parent2, TrNode_entry(child1));
|
|
if (child2) {
|
|
if (IS_LEAF_TRIE_NODE(child1))
|
|
/* child2 is a leaf node */
|
|
count++;
|
|
else
|
|
/* child1 and child2 are not leaf nodes */
|
|
count += traverse_and_count_common_entries(child1, child2);
|
|
}
|
|
child1 = TrNode_next(child1);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
static
|
|
YAP_Int traverse_and_count_entries(TrNode node) {
|
|
YAP_Int count = 0;
|
|
|
|
if (IS_HASH_NODE(node)) {
|
|
TrNode *first_bucket, *bucket;
|
|
TrHash hash;
|
|
hash = (TrHash) node;
|
|
first_bucket = TrHash_buckets(hash);
|
|
bucket = first_bucket + TrHash_num_buckets(hash);
|
|
do {
|
|
if (*--bucket) {
|
|
node = *bucket;
|
|
count += traverse_and_count_entries(node);
|
|
}
|
|
} while (bucket != first_bucket);
|
|
return count;
|
|
}
|
|
|
|
if (TrNode_next(node))
|
|
count += traverse_and_count_entries(TrNode_next(node));
|
|
if (!IS_LEAF_TRIE_NODE(node))
|
|
count += traverse_and_count_entries(TrNode_child(node));
|
|
else
|
|
count++;
|
|
return count;
|
|
}
|
|
|
|
|
|
static
|
|
void traverse_and_get_usage(TrNode node, YAP_Int depth) {
|
|
if (IS_HASH_NODE(node)) {
|
|
TrNode *first_bucket, *bucket;
|
|
TrHash hash;
|
|
hash = (TrHash) node;
|
|
first_bucket = TrHash_buckets(hash);
|
|
bucket = first_bucket + TrHash_num_buckets(hash);
|
|
do {
|
|
if (*--bucket) {
|
|
node = *bucket;
|
|
traverse_and_get_usage(node, depth);
|
|
}
|
|
} while (bucket != first_bucket);
|
|
return;
|
|
}
|
|
|
|
USAGE_NODES++;
|
|
if (TrNode_next(node))
|
|
traverse_and_get_usage(TrNode_next(node), depth);
|
|
depth++;
|
|
if (!IS_LEAF_TRIE_NODE(node)) {
|
|
traverse_and_get_usage(TrNode_child(node), depth);
|
|
} else {
|
|
USAGE_ENTRIES++;
|
|
USAGE_VIRTUAL_NODES+= depth;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
static
|
|
void traverse_and_save(TrNode node, FILE *file, int float_block) {
|
|
YAP_Term t;
|
|
|
|
if (IS_HASH_NODE(node)) {
|
|
TrNode *first_bucket, *bucket;
|
|
TrHash hash;
|
|
hash = (TrHash) node;
|
|
fprintf(file, "%lu %d ", HASH_SAVE_MARK, TrHash_num_buckets(hash));
|
|
first_bucket = TrHash_buckets(hash);
|
|
bucket = first_bucket + TrHash_num_buckets(hash);
|
|
do {
|
|
if (*--bucket) {
|
|
node = *bucket;
|
|
traverse_and_save(node, file, float_block);
|
|
}
|
|
} while (bucket != first_bucket);
|
|
return;
|
|
}
|
|
|
|
if (TrNode_next(node))
|
|
traverse_and_save(TrNode_next(node), file, float_block);
|
|
|
|
t = TrNode_entry(node);
|
|
if (float_block) {
|
|
float_block--;
|
|
fprintf(file, "%lu %lu ", FLOAT_SAVE_MARK, t);
|
|
} else if (YAP_IsPairTerm(t)) {
|
|
if (t == FloatInitTag) {
|
|
#ifdef TAG_LOW_BITS_32
|
|
float_block++;
|
|
#endif /* TAG_LOW_BITS_32 */
|
|
float_block ++;
|
|
}
|
|
fprintf(file, "%lu ", t);
|
|
} else if (YAP_IsVarTerm(t) || YAP_IsIntTerm(t))
|
|
fprintf(file, "%lu ", t);
|
|
else {
|
|
int index;
|
|
for (index = 0; index <= CURRENT_INDEX; index++)
|
|
if (AUXILIARY_TERM_STACK[index] == t)
|
|
break;
|
|
if (index > CURRENT_INDEX) {
|
|
CURRENT_INDEX = index;
|
|
if (CURRENT_INDEX == CURRENT_AUXILIARY_TERM_STACK_SIZE)
|
|
expand_auxiliary_term_stack();
|
|
AUXILIARY_TERM_STACK[CURRENT_INDEX] = t;
|
|
if (YAP_IsAtomTerm(t))
|
|
fprintf(file, "%lu %d %s%c ", ATOM_SAVE_MARK, index, YAP_AtomName(YAP_AtomOfTerm(t)), '\0');
|
|
else /* (ApplTag & t) */
|
|
fprintf(file, "%lu %d %s %d ", FUNCTOR_SAVE_MARK, index,
|
|
YAP_AtomName(YAP_NameOfFunctor((YAP_Functor)(~ApplTag & t))),
|
|
YAP_ArityOfFunctor((YAP_Functor)(~ApplTag & t)));
|
|
} else
|
|
if (YAP_IsAtomTerm(t))
|
|
fprintf(file, "%lu %d ", ATOM_SAVE_MARK, index);
|
|
else
|
|
fprintf(file, "%lu %d ", FUNCTOR_SAVE_MARK, index);
|
|
}
|
|
if (IS_LEAF_TRIE_NODE(node)) {
|
|
fprintf(file, "- ");
|
|
if (DATA_SAVE_FUNCTION)
|
|
(*DATA_SAVE_FUNCTION)(node, file);
|
|
}
|
|
else {
|
|
traverse_and_save(TrNode_child(node), file, float_block);
|
|
fprintf(file, "- ");
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
static
|
|
void traverse_and_load(TrNode parent, FILE *file) {
|
|
TrHash hash = NULL;
|
|
YAP_Term t;
|
|
|
|
if (!fscanf(file, "%lu", &t)) {
|
|
MARK_AS_LEAF_TRIE_NODE(parent);
|
|
INCREMENT_ENTRIES(CURRENT_TRIE_ENGINE);
|
|
if (DATA_LOAD_FUNCTION)
|
|
(*DATA_LOAD_FUNCTION)(parent, CURRENT_DEPTH, file);
|
|
CURRENT_DEPTH--;
|
|
return;
|
|
}
|
|
if (t == HASH_SAVE_MARK) {
|
|
/* alloc a new trie hash */
|
|
int num_buckets;
|
|
fscanf(file, "%d", &num_buckets);
|
|
new_trie_hash(hash, 0, num_buckets);
|
|
TrNode_child(parent) = (TrNode) hash;
|
|
fscanf(file, "%lu", &t);
|
|
}
|
|
do {
|
|
TrNode child;
|
|
if (t == ATOM_SAVE_MARK) {
|
|
int index;
|
|
fscanf(file, "%d", &index);
|
|
if (index > CURRENT_INDEX) {
|
|
char atom[1000];
|
|
if (CURRENT_LOAD_VERSION == 2) {
|
|
char *ptr, ch;
|
|
ptr = atom;
|
|
fgetc(file); /* skip the first empty space */
|
|
while ((ch = fgetc(file)))
|
|
*ptr++ = ch;
|
|
*ptr = '\0';
|
|
} else if (CURRENT_LOAD_VERSION == 1) {
|
|
fscanf(file, "%s", atom);
|
|
}
|
|
CURRENT_INDEX = index;
|
|
if (CURRENT_INDEX == CURRENT_AUXILIARY_TERM_STACK_SIZE)
|
|
expand_auxiliary_term_stack();
|
|
AUXILIARY_TERM_STACK[CURRENT_INDEX] = YAP_MkAtomTerm(YAP_LookupAtom(atom));
|
|
}
|
|
t = AUXILIARY_TERM_STACK[index];
|
|
} else if (t == FUNCTOR_SAVE_MARK) {
|
|
int index;
|
|
fscanf(file, "%d", &index);
|
|
if (index > CURRENT_INDEX) {
|
|
char atom[1000];
|
|
int arity;
|
|
fscanf(file, "%s %d", atom, &arity);
|
|
CURRENT_INDEX = index;
|
|
if (CURRENT_INDEX == CURRENT_AUXILIARY_TERM_STACK_SIZE)
|
|
expand_auxiliary_term_stack();
|
|
AUXILIARY_TERM_STACK[CURRENT_INDEX] = ApplTag | ((YAP_Term) YAP_MkFunctor(YAP_LookupAtom(atom), arity));
|
|
}
|
|
t = AUXILIARY_TERM_STACK[index];
|
|
} else if (t == FLOAT_SAVE_MARK)
|
|
fscanf(file, "%lu", &t);
|
|
child = trie_node_insert(parent, t, hash);
|
|
traverse_and_load(child, file);
|
|
} while (fscanf(file, "%lu", &t));
|
|
CURRENT_DEPTH--;
|
|
return;
|
|
}
|
|
|
|
|
|
static
|
|
void traverse_and_print(TrNode node, YAP_Int *arity, char *str, int str_index, int mode) {
|
|
YAP_Term t;
|
|
YAP_Int new_arity[100];
|
|
|
|
if (IS_HASH_NODE(node)) {
|
|
TrNode *first_bucket, *bucket;
|
|
TrHash hash;
|
|
hash = (TrHash) node;
|
|
first_bucket = TrHash_buckets(hash);
|
|
bucket = first_bucket + TrHash_num_buckets(hash);
|
|
do {
|
|
if (*--bucket) {
|
|
node = *bucket;
|
|
memcpy(new_arity, arity, sizeof(YAP_Int) * 100);
|
|
traverse_and_print(node, new_arity, str, str_index, mode);
|
|
}
|
|
} while (bucket != first_bucket);
|
|
return;
|
|
}
|
|
|
|
if (TrNode_next(node)) {
|
|
memcpy(new_arity, arity, sizeof(YAP_Int) * 100);
|
|
traverse_and_print(TrNode_next(node), new_arity, str, str_index, mode);
|
|
}
|
|
|
|
t = TrNode_entry(node);
|
|
if (mode == TRIE_PRINT_FLOAT) {
|
|
#ifdef TAG_LOW_BITS_32
|
|
arity[arity[0]] = (YAP_Int) t;
|
|
mode = TRIE_PRINT_FLOAT2;
|
|
} else if (mode == TRIE_PRINT_FLOAT2) {
|
|
volatile double f;
|
|
volatile YAP_Term *p;
|
|
p = (YAP_Term *)((void *) &f); /* to avoid gcc warning */
|
|
*(p + 1) = t;
|
|
*p = (YAP_Term) arity[arity[0]];
|
|
#else /* TAG_64BITS */
|
|
volatile double f;
|
|
volatile YAP_Term *p;
|
|
p = (YAP_Term *)((void *) &f); /* to avoid gcc warning */
|
|
*p = t;
|
|
#endif /* TAG_SCHEME */
|
|
str_index += sprintf(& str[str_index], "%.10f", f);
|
|
mode = TRIE_PRINT_FLOAT_END;
|
|
} else if (mode == TRIE_PRINT_FLOAT_END) {
|
|
arity[0]--;
|
|
while (arity[0]) {
|
|
arity[arity[0]]--;
|
|
if (arity[arity[0]] == 0) {
|
|
str_index += sprintf(& str[str_index], ")");
|
|
arity[0]--;
|
|
} else {
|
|
str_index += sprintf(& str[str_index], ",");
|
|
break;
|
|
}
|
|
}
|
|
mode = TRIE_PRINT_NORMAL;
|
|
} else if (YAP_IsVarTerm(t)) {
|
|
str_index += sprintf(& str[str_index], "VAR%ld", TrieVarIndex(t));
|
|
while (arity[0]) {
|
|
arity[arity[0]]--;
|
|
if (arity[arity[0]] == 0) {
|
|
str_index += sprintf(& str[str_index], ")");
|
|
arity[0]--;
|
|
} else {
|
|
str_index += sprintf(& str[str_index], ",");
|
|
break;
|
|
}
|
|
}
|
|
} else if (YAP_IsAtomTerm(t)) {
|
|
str_index += sprintf(& str[str_index], "%s", YAP_AtomName(YAP_AtomOfTerm(t)));
|
|
while (arity[0]) {
|
|
arity[arity[0]]--;
|
|
if (arity[arity[0]] == 0) {
|
|
str_index += sprintf(& str[str_index], ")");
|
|
arity[0]--;
|
|
} else {
|
|
str_index += sprintf(& str[str_index], ",");
|
|
break;
|
|
}
|
|
}
|
|
} else if (YAP_IsIntTerm(t)) {
|
|
str_index += sprintf(& str[str_index], "%ld", YAP_IntOfTerm(t));
|
|
while (arity[0]) {
|
|
arity[arity[0]]--;
|
|
if (arity[arity[0]] == 0) {
|
|
str_index += sprintf(& str[str_index], ")");
|
|
arity[0]--;
|
|
} else {
|
|
str_index += sprintf(& str[str_index], ",");
|
|
break;
|
|
}
|
|
}
|
|
} else if (YAP_IsPairTerm(t)) {
|
|
if (t == FloatInitTag) {
|
|
mode = TRIE_PRINT_FLOAT;
|
|
arity[0]++;
|
|
arity[arity[0]] = -1;
|
|
} else if (t == PairInitTag) {
|
|
str_index += sprintf(& str[str_index], "[");
|
|
arity[0]++;
|
|
arity[arity[0]] = -1;
|
|
} else if (t == CommaInitTag) {
|
|
str_index += sprintf(& str[str_index], "(");
|
|
arity[0]++;
|
|
arity[arity[0]] = -1;
|
|
} else {
|
|
if (t == PairEndTag)
|
|
str[str_index - 1] = ']';
|
|
else /* (t == CommaEndTag) */
|
|
str[str_index - 1] = ')';
|
|
arity[0]--;
|
|
while (arity[0]) {
|
|
arity[arity[0]]--;
|
|
if (arity[arity[0]] == 0) {
|
|
str_index += sprintf(& str[str_index], ")");
|
|
arity[0]--;
|
|
} else {
|
|
str_index += sprintf(& str[str_index], ",");
|
|
break;
|
|
}
|
|
}
|
|
if (arity[0]) {
|
|
traverse_and_print(TrNode_child(node), arity, str, str_index, mode);
|
|
} else {
|
|
str[str_index] = 0;
|
|
fprintf(stdout, "%s\n", str);
|
|
if (DATA_PRINT_FUNCTION)
|
|
(*DATA_PRINT_FUNCTION)(node);
|
|
}
|
|
str[str_index - 1] = ',';
|
|
return;
|
|
}
|
|
} else if (ApplTag & t) {
|
|
str_index += sprintf(& str[str_index], "%s(", YAP_AtomName(YAP_NameOfFunctor((YAP_Functor)(~ApplTag & t))));
|
|
arity[0]++;
|
|
arity[arity[0]] = YAP_ArityOfFunctor((YAP_Functor)(~ApplTag & t));
|
|
} else {
|
|
fprintf(stderr, "***************************************\n");
|
|
fprintf(stderr, " Tries core module: unknown type tag\n");
|
|
fprintf(stderr, "***************************************\n");
|
|
}
|
|
|
|
if (arity[0]) {
|
|
traverse_and_print(TrNode_child(node), arity, str, str_index, mode);
|
|
} else {
|
|
str[str_index] = 0;
|
|
fprintf(stdout, "%s\n", str);
|
|
if (DATA_PRINT_FUNCTION)
|
|
(*DATA_PRINT_FUNCTION)(node);
|
|
}
|
|
return;
|
|
}
|