1802 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1802 lines
		
	
	
		
			56 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 <stdlib.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, int *arity, char *str, int str_index, int mode);
 | |
| 
 | |
| static YAP_Term trie_to_list(TrNode node);
 | |
| static YAP_Term trie_to_list_node(TrNode node);
 | |
| static YAP_Term trie_to_list_floats(TrNode node);
 | |
| 
 | |
| 
 | |
| /* -------------------------- */
 | |
| /*       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;
 | |
| 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);
 | |
| 
 | |
| static YAP_Int TRIE_DISABLE_HASH_TABLE = 0;
 | |
| 
 | |
| 
 | |
| /* -------------------------- */
 | |
| /*     Inline Procedures      */
 | |
| /* -------------------------- */
 | |
| 
 | |
| static
 | |
| 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) || (((TrNode_entry(child) == PairEndTermTag) || (TrNode_entry(child) == PairEndEmptyTag)) && ((CURRENT_TRIE_MODE & TRIE_MODE_MINIMAL) == TRIE_MODE_MINIMAL)))
 | |
|         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) || (((TrNode_entry(child) == PairEndTermTag) || (TrNode_entry(child) == PairEndEmptyTag)) && ((CURRENT_TRIE_MODE & TRIE_MODE_MINIMAL) == TRIE_MODE_MINIMAL)))
 | |
|         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) && (TRIE_DISABLE_HASH_TABLE == 0)) {
 | |
|       /* 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
 | |
| 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
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| static
 | |
| YAP_Term trie_to_list_create_simple(const char *atom_name, TrNode node) {
 | |
|   YAP_Functor f = YAP_MkFunctor(YAP_LookupAtom(atom_name), 1);
 | |
|   YAP_Term child = trie_to_list(TrNode_child(node));  
 | |
| 
 | |
|   return YAP_MkApplTerm(f, 1, &child);
 | |
| }
 | |
| 
 | |
| 
 | |
| static
 | |
| YAP_Term trie_to_list_create_simple_end(const char *atom_name, TrNode node) {
 | |
|   YAP_Atom atom = YAP_LookupAtom(atom_name);
 | |
|   
 | |
|   if (IS_LEAF_TRIE_NODE(node)) {
 | |
|     return YAP_MkAtomTerm(atom);
 | |
|   } else {
 | |
|     YAP_Functor f = YAP_MkFunctor(atom, 1);
 | |
|     YAP_Term child = trie_to_list(TrNode_child(node));    
 | |
|     return YAP_MkApplTerm(f, 1, &child);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| static
 | |
| YAP_Term trie_to_list_create_two(const char *atom_name, TrNode node, YAP_Term operand) {
 | |
|   YAP_Atom atom = YAP_LookupAtom(atom_name);
 | |
|   
 | |
|   if(IS_LEAF_TRIE_NODE(node)) {
 | |
|     YAP_Functor f = YAP_MkFunctor(atom, 1);
 | |
|     return YAP_MkApplTerm(f, 1, &operand);
 | |
|   } else {
 | |
|     YAP_Functor f = YAP_MkFunctor(atom, 2);
 | |
|     YAP_Term args[2] = {
 | |
|       operand, trie_to_list(TrNode_child(node))
 | |
|     };
 | |
|     return YAP_MkApplTerm(f, 2, args);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /* -------------------------- */
 | |
| /*            API             */     
 | |
| /* -------------------------- */
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void core_trie_set_mode(YAP_Int mode) {
 | |
|   CURRENT_TRIE_MODE = mode;
 | |
|   return;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| YAP_Int core_trie_get_mode(void) {
 | |
|   return CURRENT_TRIE_MODE;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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)) {
 | |
|     (void) POP_DOWN(stack_vars);
 | |
|     *((YAP_Term *)*stack_vars) = *stack_vars;
 | |
|   }
 | |
|   if (depth)
 | |
|     *depth = CURRENT_DEPTH;
 | |
|   return node;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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)) {
 | |
|     (void) POP_DOWN(stack_vars);
 | |
|     *((YAP_Term *)*stack_vars) = *stack_vars;
 | |
|   }
 | |
|   return node;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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");
 | |
|     fflush(file);
 | |
|   }
 | |
|   return;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| TrNode core_trie_load(TrEngine engine, FILE *file, void (*load_function)(TrNode, YAP_Int, FILE *)) {
 | |
|   TrNode node;
 | |
|   char version[15];
 | |
|   fpos_t curpos;
 | |
|   int n;
 | |
| 
 | |
|   n = fscanf(file, "%14s", version);
 | |
|   if (fgetpos(file, &curpos))
 | |
|     return NULL;
 | |
| 
 | |
|   if (!strcmp(version, "BEGIN_TRIE_v2")) {
 | |
|     fseek(file, -11, SEEK_END);
 | |
|     n = 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");  
 | |
|       fflush(stderr);
 | |
|       return NULL;
 | |
|     }
 | |
|     if (fsetpos(file, &curpos))
 | |
|       return NULL;
 | |
|     CURRENT_LOAD_VERSION = 2;
 | |
|   } else if (!strcmp(version, "BEGIN_TRIE")) {
 | |
|     fseek(file, -8, SEEK_END);
 | |
|     n = fscanf(file, "%s", version);
 | |
|     if (strcmp(version, "END_TRIE")) {
 | |
|       fprintf(stderr, "******************************************\n");
 | |
|       fprintf(stderr, "  Tries core module: trie file corrupted\n");
 | |
|       fprintf(stderr, "******************************************\n");  
 | |
|       fflush(stderr);
 | |
|       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");  
 | |
|     fflush(stderr);
 | |
|     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);
 | |
|   if (n) n = 0; // just added to remove the warning of not used!
 | |
|   return node;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void core_trie_print(TrNode node, void (*print_function)(TrNode)) {
 | |
|   DATA_PRINT_FUNCTION = print_function;
 | |
|   if (TrNode_child(node)) {
 | |
|     int arity[1000];
 | |
|     char str[10000];
 | |
|     arity[0] = 0;
 | |
|     traverse_and_print(TrNode_child(node), arity, str, 0, TRIE_PRINT_NORMAL);
 | |
|   } else
 | |
|     fprintf(stdout, "(empty)\n");
 | |
|   fflush(stdout);
 | |
|   return;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void core_disable_hash_table(void) {
 | |
|   TRIE_DISABLE_HASH_TABLE = 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void core_enable_hash_table(void) {
 | |
|   TRIE_DISABLE_HASH_TABLE = 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| YAP_Term core_trie_to_list(TrNode node) {
 | |
|   TrNode root = TrNode_child(node);
 | |
|   
 | |
|   if (root)
 | |
|     return trie_to_list(root);
 | |
|   else
 | |
|     return YAP_MkAtomTerm(YAP_LookupAtom("empty"));
 | |
| }
 | |
| 
 | |
| 
 | |
| /* -------------------------- */
 | |
| /*      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 union {
 | |
|       double f;
 | |
|       YAP_Term p[SIZE_FLOAT_AS_TERM];
 | |
|     } tf;  /* to avoid gcc warning */
 | |
|     tf.f = YAP_FloatOfTerm(t);
 | |
|     node = trie_node_check_insert(node, FloatInitTag);
 | |
|     node = trie_node_check_insert(node, tf.p[0]);
 | |
| #ifdef TAG_LOW_BITS_32
 | |
|     node = trie_node_check_insert(node, tf.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_REVERSE) == TRIE_MODE_STANDARD) {
 | |
|       do {
 | |
|         node = put_entry(node, YAP_HeadOfTerm(t));
 | |
|         t = YAP_Deref(YAP_TailOfTerm(t));
 | |
|       } while (YAP_IsPairTerm(t));
 | |
|       if (t == YAP_TermNil()) {
 | |
|         node = trie_node_check_insert(node, PairEndEmptyTag);
 | |
|       } else {
 | |
|         node = put_entry(node, t);
 | |
|         node = trie_node_check_insert(node, PairEndTermTag);
 | |
|       }
 | |
|     } else if (CURRENT_TRIE_MODE & TRIE_MODE_REVERSE) { /* 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));
 | |
|       if (t == YAP_TermNil()) {
 | |
|         while (STACK_NOT_EMPTY(stack_args, stack_list))
 | |
|           node = put_entry(node, POP_UP(stack_args));
 | |
|         node = trie_node_check_insert(node, PairEndEmptyTag);
 | |
|       } else {
 | |
|         PUSH_DOWN(stack_args, t, stack_vars);
 | |
|         while (STACK_NOT_EMPTY(stack_args, stack_list))
 | |
|           node = put_entry(node, POP_UP(stack_args));
 | |
|         node = trie_node_check_insert(node, PairEndTermTag);
 | |
|       }
 | |
|     }
 | |
|   } 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");
 | |
|     fflush(stderr);
 | |
|   }
 | |
|   
 | |
|   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 union {
 | |
|       double f;
 | |
|       YAP_Term p[SIZE_FLOAT_AS_TERM];
 | |
|     } tf;  /* to avoid gcc warning */
 | |
|     tf.f = YAP_FloatOfTerm(t);
 | |
|     if (!(node = trie_node_check(node, FloatInitTag)))
 | |
|       return NULL;
 | |
|     if (!(node = trie_node_check(node, tf.p[0])))
 | |
|       return NULL;
 | |
| #ifdef TAG_LOW_BITS_32
 | |
|     if (!(node = trie_node_check(node, tf.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_REVERSE) == TRIE_MODE_STANDARD) {
 | |
|       do {
 | |
|         if (!(node = check_entry(node, YAP_HeadOfTerm(t))))
 | |
|           return NULL;
 | |
|         t = YAP_Deref(YAP_TailOfTerm(t));
 | |
|       } while (YAP_IsPairTerm(t));
 | |
|       if (t == YAP_TermNil()) {
 | |
|         if (!(node = trie_node_check(node, PairEndEmptyTag)))
 | |
|           return NULL;
 | |
|       } else {
 | |
|         if (!(node = check_entry(node, t)))
 | |
|           return NULL;
 | |
|         if (!(node = trie_node_check(node, PairEndTermTag)))
 | |
|           return NULL;
 | |
|       }
 | |
|     } else if (CURRENT_TRIE_MODE & TRIE_MODE_REVERSE) { /* 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));
 | |
|       if (t == YAP_TermNil()) {
 | |
|         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, PairEndEmptyTag)))
 | |
|           return NULL;
 | |
|       } else {
 | |
|         PUSH_DOWN(stack_args, t, stack_vars);
 | |
|         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, PairEndTermTag)))
 | |
|           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");
 | |
|     fflush(stderr);
 | |
|   }
 | |
|   
 | |
|   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");
 | |
|           fflush(stderr);
 | |
|         }
 | |
|         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 == PairInitTag) {
 | |
|         YAP_Term t2;
 | |
|         if ((CURRENT_TRIE_MODE & TRIE_MODE_REVERSE) == 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);
 | |
|           }
 | |
|         } else if (CURRENT_TRIE_MODE & TRIE_MODE_REVERSE) { /* TRIE_MODE_REVERSE */
 | |
|           YAP_Term *stack_aux = stack_mark;
 | |
|           t = *stack_aux;
 | |
|           if (t == YAP_TermNil())
 | |
|             stack_aux--;
 | |
|           else
 | |
|             t = POP_DOWN(stack_args);
 | |
|           while (STACK_NOT_EMPTY(stack_args, stack_aux)) {
 | |
|             t2 = POP_DOWN(stack_args);
 | |
|             t = YAP_MkPairTerm(t2, t);
 | |
|           }
 | |
|         }
 | |
|         stack_args = stack_mark;
 | |
|         *cur_node = node;
 | |
|         return t;
 | |
|       } else if (t == PairEndEmptyTag) {
 | |
|         t = YAP_TermNil();
 | |
|         PUSH_UP(stack_args, t, stack_vars);
 | |
|         node = TrNode_parent(node);
 | |
|         t = get_entry(node, &stack_args[1], &node);
 | |
|         PUSH_UP(stack_args, t, stack_vars);
 | |
|       } else if (t == PairEndTermTag) {
 | |
|         node = TrNode_parent(node);
 | |
|         t = get_entry(node, stack_args, &node);
 | |
|         PUSH_UP(stack_args, t, stack_vars);
 | |
|       } 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 union {
 | |
|           double f;
 | |
|           YAP_Term p[SIZE_FLOAT_AS_TERM];
 | |
|         } tf;  /* to avoid gcc warning */
 | |
| #ifdef TAG_LOW_BITS_32
 | |
|         node = TrNode_parent(node);
 | |
|         tf.p[1] = TrNode_entry(node);
 | |
| #endif /* TAG_LOW_BITS_32 */
 | |
|         node = TrNode_parent(node);
 | |
|         tf.p[0] = TrNode_entry(node);
 | |
|         node = TrNode_parent(node); /* ignore FloatInitTag */
 | |
|         t = YAP_MkFloatTerm(tf.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");
 | |
|       fflush(stderr);
 | |
|     }
 | |
|     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, UInt_FORMAT " %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, UInt_FORMAT " " UInt_FORMAT "  ", 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, UInt_FORMAT " ", t);
 | |
|   } else if (YAP_IsVarTerm(t) || YAP_IsIntTerm(t))
 | |
|     fprintf(file, UInt_FORMAT" ", 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, UInt_FORMAT " %d %s%c ", ATOM_SAVE_MARK, index, YAP_AtomName(YAP_AtomOfTerm(t)), '\0');
 | |
|       else  /* (ApplTag & t) */
 | |
|         fprintf(file, UInt_FORMAT " %d %s " UInt_FORMAT " ", 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, UInt_FORMAT " %d ", ATOM_SAVE_MARK, index);
 | |
|       else
 | |
|         fprintf(file, UInt_FORMAT " %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;
 | |
|   int n;
 | |
| 
 | |
|   if (!fscanf(file, UInt_FORMAT , &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;
 | |
|     n = fscanf(file, "%d", &num_buckets);
 | |
|     new_trie_hash(hash, 0, num_buckets);
 | |
|     TrNode_child(parent) = (TrNode) hash;
 | |
|     n = fscanf(file, UInt_FORMAT , &t);
 | |
|   }
 | |
|   do {
 | |
|     TrNode child;
 | |
|     if (t == ATOM_SAVE_MARK) {
 | |
|       int index;
 | |
|       n = 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) {
 | |
|           n = 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;
 | |
|       n = fscanf(file, "%d", &index);
 | |
|       if (index > CURRENT_INDEX) {
 | |
|         char atom[1000];
 | |
|         int arity;
 | |
|         n = 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)
 | |
|       n = fscanf(file, UInt_FORMAT , &t);
 | |
|     child = trie_node_insert(parent, t, hash);
 | |
|     traverse_and_load(child, file);
 | |
|   } while (fscanf(file, UInt_FORMAT , &t));
 | |
|   CURRENT_DEPTH--;
 | |
|   if (n) n = 0; // just added to remove the warning of not used!
 | |
|   return;
 | |
| }
 | |
| 
 | |
| 
 | |
| static
 | |
| void traverse_and_print(TrNode node, int *arity, char *str, int str_index, int mode) {
 | |
|   YAP_Term t;
 | |
|   int last_pair_mark = -arity[arity[0]];
 | |
| 
 | |
|   if (IS_HASH_NODE(node)) {
 | |
|     int *current_arity = (int *) malloc(sizeof(int) * (arity[0] + 1));
 | |
|     TrNode *first_bucket, *bucket;
 | |
|     TrHash hash;
 | |
|     hash = (TrHash) node;
 | |
|     first_bucket = TrHash_buckets(hash);
 | |
|     bucket = first_bucket + TrHash_num_buckets(hash);
 | |
|     memcpy(current_arity, arity, sizeof(int) * (arity[0] + 1));
 | |
|     do {
 | |
|       if (*--bucket) {
 | |
|         node = *bucket;
 | |
|         traverse_and_print(node, arity, str, str_index, mode);
 | |
|         memcpy(arity, current_arity, sizeof(int) * (current_arity[0] + 1));
 | |
|         if (mode != TRIE_PRINT_FLOAT2 && arity[arity[0]] < 0) {
 | |
|           /* restore possible PairEndEmptyTag/PairEndTermTag/CommaEndTag side-effect */
 | |
|           if (str_index > 0 && str[str_index - 1] != '[')
 | |
|             str[str_index - 1] = ',';
 | |
|           /* restore possible PairEndTermTag side-effect */
 | |
|           if (str[last_pair_mark] == '|')
 | |
|             str[last_pair_mark] = ',';
 | |
|         }
 | |
|       }
 | |
|     } while (bucket != first_bucket);
 | |
|     free(current_arity);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (TrNode_next(node)) {
 | |
|     int *current_arity = (int *) malloc(sizeof(int) * (arity[0] + 1));
 | |
|     memcpy(current_arity, arity, sizeof(int) * (arity[0] + 1));
 | |
|     traverse_and_print(TrNode_next(node), arity, str, str_index, mode);
 | |
|     memcpy(arity, current_arity, sizeof(int) * (current_arity[0] + 1));
 | |
|     if (mode != TRIE_PRINT_FLOAT2 && arity[arity[0]] < 0) {
 | |
|       /* restore possible PairEndEmptyTag/PairEndTermTag/CommaEndTag side-effect */
 | |
|       if (str_index > 0 && str[str_index - 1] != '[')
 | |
|         str[str_index - 1] = ',';
 | |
|       /* restore possible PairEndTermTag side-effect */
 | |
|       if (str[last_pair_mark] == '|')
 | |
|         str[last_pair_mark] = ',';
 | |
|     }
 | |
|     free(current_arity);
 | |
|   }
 | |
| 
 | |
|   /* update position for possible PairEndTermTag side-effect */
 | |
|   if (mode != TRIE_PRINT_FLOAT2 && arity[arity[0]] < 0 && str_index > 1)
 | |
|     arity[arity[0]] = -str_index + 1;
 | |
| 
 | |
|   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 union {
 | |
|       double f;
 | |
|       YAP_Term p[SIZE_FLOAT_AS_TERM];
 | |
|     } tf;  /* to avoid gcc warning */
 | |
|     tf.p[1] = t;
 | |
|     tf.p[0] = (YAP_Term) arity[arity[0]];
 | |
|     arity[arity[0]] = -1;
 | |
| #else /* TAG_64BITS */
 | |
|     volatile union {
 | |
|       double f;
 | |
|       YAP_Term p[SIZE_FLOAT_AS_TERM];
 | |
|     } tf;  /* to avoid gcc warning */
 | |
|     tf.p[0] = t;
 | |
| #endif /* TAG_SCHEME */
 | |
|     str_index += sprintf(& str[str_index], "%.15g", tf.f);
 | |
|     mode = TRIE_PRINT_FLOAT_END;
 | |
|   } else if (mode == TRIE_PRINT_FLOAT_END) {
 | |
|     arity[0]--;
 | |
|     while (arity[0]) {
 | |
|       if (arity[arity[0]] == 1) {
 | |
|         str_index += sprintf(& str[str_index], ")");
 | |
|         arity[0]--;
 | |
|       } else {
 | |
|         if (arity[arity[0]] > 1)
 | |
|           arity[arity[0]]--;
 | |
|         str_index += sprintf(& str[str_index], ",");
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|     mode = TRIE_PRINT_NORMAL;
 | |
|   } else if (YAP_IsVarTerm(t)) {
 | |
|     str_index += sprintf(& str[str_index], "VAR" UInt_FORMAT, TrieVarIndex(t));
 | |
|     while (arity[0]) {
 | |
|       if (arity[arity[0]] == 1) {
 | |
|         str_index += sprintf(& str[str_index], ")");
 | |
|         arity[0]--;
 | |
|       } else {
 | |
|         if (arity[arity[0]] > 1)
 | |
|           arity[arity[0]]--;
 | |
|         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]) {
 | |
|       if (arity[arity[0]] == 1) {
 | |
|         str_index += sprintf(& str[str_index], ")");
 | |
|         arity[0]--;
 | |
|       } else {
 | |
|         if (arity[arity[0]] > 1)
 | |
|           arity[arity[0]]--;
 | |
|         str_index += sprintf(& str[str_index], ",");
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   } else if (YAP_IsIntTerm(t)) {
 | |
|     str_index += sprintf(& str[str_index], UInt_FORMAT , YAP_IntOfTerm(t));
 | |
|     while (arity[0]) {
 | |
|       if (arity[arity[0]] == 1) {
 | |
|         str_index += sprintf(& str[str_index], ")");
 | |
|         arity[0]--;
 | |
|       } else {
 | |
|         if (arity[arity[0]] > 1)
 | |
|           arity[arity[0]]--;
 | |
|         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 == PairEndEmptyTag)
 | |
|         str[str_index - 1] = ']';
 | |
|       else if (t == PairEndTermTag) {
 | |
|         str[last_pair_mark] = '|';
 | |
|         str[str_index - 1] = ']';
 | |
|       } else /*   (t == CommaEndTag)   */
 | |
|         str[str_index - 1] = ')';
 | |
|       arity[0]--;
 | |
|       while (arity[0]) {
 | |
|         if (arity[arity[0]] == 1) {
 | |
|           str_index += sprintf(& str[str_index], ")");
 | |
|           arity[0]--;
 | |
|         } else {
 | |
|           if (arity[arity[0]] > 1)
 | |
|             arity[arity[0]]--;
 | |
|           str_index += sprintf(& str[str_index], ",");
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   } 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");
 | |
|     fflush(stderr);
 | |
|   }
 | |
| 
 | |
|   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;
 | |
| }
 | |
| 
 | |
| 
 | |
| static
 | |
| YAP_Term trie_to_list(TrNode node) {
 | |
|   YAP_Term tail = YAP_MkAtomTerm(YAP_LookupAtom("[]"));
 | |
| 
 | |
| #define CONSUME_NODE_LIST                                  \
 | |
|   do {                                                     \
 | |
|     /* add node result to list */                          \
 | |
|     tail = YAP_MkPairTerm(trie_to_list_node(node), tail);  \
 | |
|   } while((node = TrNode_next(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);
 | |
|     
 | |
|     /* iterate through valid hash positions and consume each list */
 | |
|     do {
 | |
|       if (*--bucket) {
 | |
|         node = *bucket;
 | |
|         CONSUME_NODE_LIST;
 | |
|       }
 | |
|     } while (bucket != first_bucket);
 | |
|   } else {
 | |
|     CONSUME_NODE_LIST;
 | |
|   }  
 | |
| #undef CONSUME_NODE_LIST
 | |
| 
 | |
|   /* return list of trie options at this level */
 | |
|   return tail;
 | |
| }
 | |
| 
 | |
| 
 | |
| static
 | |
| YAP_Term trie_to_list_node(TrNode node) {
 | |
|   YAP_Term t = TrNode_entry(node);
 | |
|   
 | |
|   if(YAP_IsIntTerm(t) || YAP_IsAtomTerm(t)) {
 | |
|     return trie_to_list_create_two(YAP_IsIntTerm(t) ? "int" : "atom", node, t);
 | |
|   } else if (YAP_IsVarTerm(t)) {
 | |
|     int index = TrieVarIndex(t);
 | |
|     YAP_Term index_term = YAP_MkIntTerm((YAP_Int)index);
 | |
|     return trie_to_list_create_two("var", node, index_term);
 | |
|   } else if (YAP_IsPairTerm(t)) {
 | |
|     if(t == FloatInitTag) {
 | |
|       node = TrNode_child(node); /* consume FloatInitTag */      
 | |
|       YAP_Functor f = YAP_MkFunctor(YAP_LookupAtom("floats"), 1);
 | |
|       YAP_Term child = trie_to_list_floats(node);
 | |
|       return YAP_MkApplTerm(f, 1, &child);
 | |
|     } else if(t == PairInitTag) {
 | |
|       return trie_to_list_create_simple("list", node);
 | |
|     } else if (t == PairEndEmptyTag) {
 | |
|       return trie_to_list_create_simple_end("endlist", node);
 | |
|     } else if (t == CommaInitTag) {
 | |
|       return trie_to_list_create_simple("comma", node);
 | |
|     } else if (t == CommaEndTag) {
 | |
|       return trie_to_list_create_simple_end("endcomma", node);
 | |
|     }
 | |
|   } else if (ApplTag & t) {
 | |
|     YAP_Functor f = (YAP_Functor)(~ApplTag & t);
 | |
|     int arity = YAP_ArityOfFunctor(f);
 | |
|     YAP_Functor new_f = YAP_MkFunctor(YAP_LookupAtom("functor"), 3);
 | |
|     YAP_Term args[3] = {
 | |
|       YAP_MkAtomTerm(YAP_NameOfFunctor(f)),
 | |
|       YAP_MkIntTerm((YAP_Int)arity),
 | |
|       trie_to_list(TrNode_child(node))
 | |
|     };
 | |
|     return YAP_MkApplTerm(new_f, 3, args);
 | |
|   }
 | |
|   fprintf(stderr, "***************************************\n");
 | |
|   fprintf(stderr, "  Tries core module: unknown type tag\n");
 | |
|   fprintf(stderr, "***************************************\n");
 | |
|   fflush(stderr);
 | |
|   
 | |
|   return YAP_MkAtomTerm(YAP_LookupAtom("fail"));
 | |
| }
 | |
| 
 | |
| 
 | |
| #define PUSH_NEW_FLOAT_TERM(val)                                                     \
 | |
|         result = YAP_MkPairTerm(                                                     \
 | |
|         trie_to_list_create_two("float", TrNode_child(node), YAP_MkFloatTerm(val)),  \
 | |
|         result);
 | |
| 
 | |
| 
 | |
| #ifdef TAG_LOW_BITS_32
 | |
| 
 | |
| YAP_Term trie_to_list_floats_tag_low_32(YAP_Term result, TrNode node, volatile YAP_Term *p, volatile double *f) {
 | |
|   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) {
 | |
|         node = *bucket;
 | |
|         do {
 | |
|           p[1] = TrNode_entry(node);
 | |
|           PUSH_NEW_FLOAT_TERM(*f);
 | |
|         } while((node = TrNode_next(node)));
 | |
|       }
 | |
|     } while (bucket != first_bucket);
 | |
|   } else {
 | |
|     do {
 | |
|       p[1] = TrNode_entry(node);
 | |
|       PUSH_NEW_FLOAT_TERM(*f);
 | |
|     } while((node = TrNode_next(node)));
 | |
|   }
 | |
|   
 | |
|   return result;
 | |
| }
 | |
| #endif /* TAG_LOW_BITS_32 */
 | |
| 
 | |
| 
 | |
| static
 | |
| YAP_Term trie_to_list_floats(TrNode node) {
 | |
|   volatile union {
 | |
|     double f;
 | |
|     YAP_Term p[SIZE_FLOAT_AS_TERM];
 | |
|   } tf;  /* to avoid gcc warning */
 | |
|   YAP_Term result = YAP_MkAtomTerm(YAP_LookupAtom("[]"));
 | |
| 
 | |
|   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) {
 | |
|         node = *bucket;
 | |
|         do {
 | |
|           tf.p[0] = TrNode_entry(node);
 | |
| #ifdef TAG_LOW_BITS_32
 | |
|           result = trie_to_list_floats_tag_low_32(result, TrNode_child(node), &tf.p, &tf.f);
 | |
| #else
 | |
|           PUSH_NEW_FLOAT_TERM(tf.f);
 | |
| #endif /* TAG_LOW_BITS_32 */
 | |
|         } while((node = TrNode_next(node)));
 | |
|       }
 | |
|     } while (bucket != first_bucket);
 | |
|   } else {
 | |
|     do {
 | |
|       tf.p[0] = TrNode_entry(node);
 | |
| #ifdef TAG_LOW_BITS_32
 | |
|       result = trie_to_list_floats_tag_low_32(result, TrNode_child(node), &tf.p, &tf.f);
 | |
| #else
 | |
|       PUSH_NEW_FLOAT_TERM(tf.f);
 | |
| #endif /* TAG_LOW_BITS_32 */
 | |
|     } while((node = TrNode_next(node)));
 | |
|   }
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| #undef PUSH_NEW_FLOAT_TERM
 | |
| 
 | |
| 
 | |
| #include "core_dbtries.c"
 |