759 lines
26 KiB
OpenEdge ABL
759 lines
26 KiB
OpenEdge ABL
/************************************************************************
|
|
** **
|
|
** The YapTab/YapOr/OPTYap systems **
|
|
** **
|
|
** YapTab extends the Yap Prolog engine to support sequential tabling **
|
|
** YapOr extends the Yap Prolog engine to support or-parallelism **
|
|
** OPTYap extends the Yap Prolog engine to support or-parallel tabling **
|
|
** **
|
|
** **
|
|
** Yap Prolog was developed at University of Porto, Portugal **
|
|
** **
|
|
************************************************************************/
|
|
|
|
/*********************
|
|
** Macros **
|
|
*********************/
|
|
|
|
#undef NEW_SUBGOAL_TRIE_NODE
|
|
#undef NEW_ANSWER_TRIE_NODE
|
|
#undef NEW_GLOBAL_TRIE_NODE
|
|
#undef LOCK_NODE
|
|
#undef UNLOCK_NODE
|
|
|
|
#ifdef IS_GLOBAL_TRIE_REFERENCE
|
|
#define NEW_SUBGOAL_TRIE_NODE(NODE, ENTRY, CHILD, PARENT, NEXT) \
|
|
INCREMENT_GLOBAL_TRIE_REFERENCE(ENTRY); \
|
|
new_subgoal_trie_node(NODE, ENTRY, CHILD, PARENT, NEXT)
|
|
#define NEW_ANSWER_TRIE_NODE(NODE, INSTR, ENTRY, CHILD, PARENT, NEXT) \
|
|
INCREMENT_GLOBAL_TRIE_REFERENCE(ENTRY); \
|
|
new_answer_trie_node(NODE, INSTR, ENTRY, CHILD, PARENT, NEXT)
|
|
#define NEW_GLOBAL_TRIE_NODE(NODE, ENTRY, CHILD, PARENT, NEXT) \
|
|
INCREMENT_GLOBAL_TRIE_REFERENCE(ENTRY); \
|
|
new_global_trie_node(NODE, ENTRY, CHILD, PARENT, NEXT)
|
|
#else
|
|
#define NEW_SUBGOAL_TRIE_NODE(NODE, ENTRY, CHILD, PARENT, NEXT) \
|
|
new_subgoal_trie_node(NODE, ENTRY, CHILD, PARENT, NEXT)
|
|
#define NEW_ANSWER_TRIE_NODE(NODE, INSTR, ENTRY, CHILD, PARENT, NEXT) \
|
|
new_answer_trie_node(NODE, INSTR, ENTRY, CHILD, PARENT, NEXT)
|
|
#define NEW_GLOBAL_TRIE_NODE(NODE, ENTRY, CHILD, PARENT, NEXT) \
|
|
new_global_trie_node(NODE, ENTRY, CHILD, PARENT, NEXT)
|
|
#endif /* IS_GLOBAL_TRIE_REFERENCE */
|
|
|
|
#if defined(TABLE_LOCK_AT_WRITE_LEVEL)
|
|
#define LOCK_NODE(NODE) LOCK_TABLE(NODE)
|
|
#define UNLOCK_NODE(NODE) UNLOCK_TABLE(NODE)
|
|
#elif defined(TABLE_LOCK_AT_NODE_LEVEL)
|
|
#define LOCK_NODE(NODE) TRIE_LOCK(TrNode_lock(NODE))
|
|
#define UNLOCK_NODE(NODE) UNLOCK(TrNode_lock(NODE))
|
|
#else
|
|
#define LOCK_NODE(NODE)
|
|
#define UNLOCK_NODE(NODE)
|
|
#endif /* TABLE_LOCK_LEVEL */
|
|
|
|
|
|
|
|
/************************************************************************
|
|
** subgoal_trie_check_insert_(gt)_token **
|
|
************************************************************************/
|
|
|
|
#ifdef INCLUDE_SUBGOAL_TRIE_CHECK_INSERT
|
|
#ifdef TABLE_LOCK_AT_WRITE_LEVEL
|
|
#ifdef IS_GLOBAL_TRIE_REFERENCE
|
|
static inline sg_node_ptr subgoal_trie_check_insert_gt_token(tab_ent_ptr tab_ent, sg_node_ptr parent_node, Term t) {
|
|
#else
|
|
static inline sg_node_ptr subgoal_trie_check_insert_token(tab_ent_ptr tab_ent, sg_node_ptr parent_node, Term t) {
|
|
#endif /* IS_GLOBAL_TRIE_REFERENCE */
|
|
sg_node_ptr child_node;
|
|
sg_hash_ptr hash;
|
|
|
|
child_node = TrNode_child(parent_node);
|
|
if (child_node == NULL) {
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, NULL);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
LOCK_NODE(parent_node);
|
|
if (TrNode_child(parent_node)) {
|
|
sg_node_ptr chain_node = TrNode_child(parent_node);
|
|
if (IS_SUBGOAL_TRIE_HASH(chain_node)) {
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
FREE_SUBGOAL_TRIE_NODE(child_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
UNLOCK_NODE(parent_node);
|
|
hash = (sg_hash_ptr) chain_node;
|
|
goto subgoal_trie_hash;
|
|
}
|
|
do {
|
|
if (TrNode_entry(chain_node) == t) {
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
FREE_SUBGOAL_TRIE_NODE(child_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
UNLOCK_NODE(parent_node);
|
|
return chain_node;
|
|
}
|
|
chain_node = TrNode_next(chain_node);
|
|
} while (chain_node);
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
TrNode_next(child_node) = TrNode_child(parent_node);
|
|
#else
|
|
NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, TrNode_child(parent_node));
|
|
} else {
|
|
NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, NULL);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
}
|
|
TrNode_child(parent_node) = child_node;
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
|
|
if (! IS_SUBGOAL_TRIE_HASH(child_node)) {
|
|
sg_node_ptr first_node = child_node;
|
|
int count_nodes = 0;
|
|
do {
|
|
if (TrNode_entry(child_node) == t) {
|
|
return child_node;
|
|
}
|
|
count_nodes++;
|
|
child_node = TrNode_next(child_node);
|
|
} while (child_node);
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, first_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
LOCK_NODE(parent_node);
|
|
if (first_node != TrNode_child(parent_node)) {
|
|
sg_node_ptr chain_node = TrNode_child(parent_node);
|
|
if (IS_SUBGOAL_TRIE_HASH(chain_node)) {
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
FREE_SUBGOAL_TRIE_NODE(child_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
UNLOCK_NODE(parent_node);
|
|
hash = (sg_hash_ptr) chain_node;
|
|
goto subgoal_trie_hash;
|
|
}
|
|
do {
|
|
if (TrNode_entry(chain_node) == t) {
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
FREE_SUBGOAL_TRIE_NODE(child_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
UNLOCK_NODE(parent_node);
|
|
return chain_node;
|
|
}
|
|
count_nodes++;
|
|
chain_node = TrNode_next(chain_node);
|
|
} while (chain_node != first_node);
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
TrNode_next(child_node) = TrNode_child(parent_node);
|
|
#else
|
|
NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, TrNode_child(parent_node));
|
|
} else {
|
|
NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, first_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
}
|
|
count_nodes++;
|
|
if (count_nodes >= MAX_NODES_PER_TRIE_LEVEL) {
|
|
/* alloc a new hash */
|
|
sg_node_ptr chain_node, next_node, *bucket;
|
|
new_subgoal_trie_hash(hash, count_nodes, tab_ent);
|
|
chain_node = child_node;
|
|
do {
|
|
bucket = Hash_bucket(hash, HASH_ENTRY(TrNode_entry(chain_node), BASE_HASH_BUCKETS - 1));
|
|
next_node = TrNode_next(chain_node);
|
|
TrNode_next(chain_node) = *bucket;
|
|
*bucket = chain_node;
|
|
chain_node = next_node;
|
|
} while (chain_node);
|
|
TrNode_child(parent_node) = (sg_node_ptr) hash;
|
|
} else {
|
|
TrNode_child(parent_node) = child_node;
|
|
}
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
|
|
hash = (sg_hash_ptr) child_node;
|
|
subgoal_trie_hash:
|
|
{ /* trie nodes with hashing */
|
|
sg_node_ptr *bucket, first_node;
|
|
int seed, count_nodes = 0;
|
|
|
|
seed = Hash_seed(hash);
|
|
bucket = Hash_bucket(hash, HASH_ENTRY(t, seed));
|
|
first_node = child_node = *bucket;
|
|
while (child_node) {
|
|
if (TrNode_entry(child_node) == t) {
|
|
return child_node;
|
|
}
|
|
count_nodes++;
|
|
child_node = TrNode_next(child_node);
|
|
}
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, first_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
LOCK_NODE(parent_node);
|
|
if (seed != Hash_seed(hash)) {
|
|
/* the hash has been expanded */
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
FREE_SUBGOAL_TRIE_NODE(child_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
UNLOCK_NODE(parent_node);
|
|
goto subgoal_trie_hash;
|
|
}
|
|
if (first_node != *bucket) {
|
|
sg_node_ptr chain_node = *bucket;
|
|
do {
|
|
if (TrNode_entry(chain_node) == t) {
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
FREE_SUBGOAL_TRIE_NODE(child_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
UNLOCK_NODE(parent_node);
|
|
return chain_node;
|
|
}
|
|
count_nodes++;
|
|
chain_node = TrNode_next(chain_node);
|
|
} while (chain_node != first_node);
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
TrNode_next(child_node) = *bucket;
|
|
#else
|
|
NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, *bucket);
|
|
} else {
|
|
NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, first_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
}
|
|
*bucket = child_node;
|
|
Hash_num_nodes(hash)++;
|
|
count_nodes++;
|
|
if (count_nodes >= MAX_NODES_PER_BUCKET && Hash_num_nodes(hash) > Hash_num_buckets(hash)) {
|
|
/* expand current hash */
|
|
sg_node_ptr chain_node, next_node, *first_old_bucket, *old_bucket;
|
|
first_old_bucket = Hash_buckets(hash);
|
|
old_bucket = first_old_bucket + Hash_num_buckets(hash);
|
|
Hash_num_buckets(hash) *= 2;
|
|
ALLOC_HASH_BUCKETS(Hash_buckets(hash), Hash_num_buckets(hash));
|
|
seed = Hash_seed(hash);
|
|
do {
|
|
if (*--old_bucket) {
|
|
chain_node = *old_bucket;
|
|
do {
|
|
bucket = Hash_bucket(hash, HASH_ENTRY(TrNode_entry(chain_node), seed));
|
|
next_node = TrNode_next(chain_node);
|
|
TrNode_next(chain_node) = *bucket;
|
|
*bucket = chain_node;
|
|
chain_node = next_node;
|
|
} while (chain_node);
|
|
}
|
|
} while (old_bucket != first_old_bucket);
|
|
FREE_HASH_BUCKETS(first_old_bucket);
|
|
}
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
}
|
|
#else /* TABLE_LOCK_AT_ENTRY_LEVEL || TABLE_LOCK_AT_NODE_LEVEL || ! YAPOR */
|
|
#ifdef IS_GLOBAL_TRIE_REFERENCE
|
|
static inline sg_node_ptr subgoal_trie_check_insert_gt_token(tab_ent_ptr tab_ent, sg_node_ptr parent_node, Term t) {
|
|
#else
|
|
static inline sg_node_ptr subgoal_trie_check_insert_token(tab_ent_ptr tab_ent, sg_node_ptr parent_node, Term t) {
|
|
#endif /* IS_GLOBAL_TRIE_REFERENCE */
|
|
sg_node_ptr child_node;
|
|
|
|
LOCK_NODE(parent_node);
|
|
child_node = TrNode_child(parent_node);
|
|
if (child_node == NULL) {
|
|
NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, NULL);
|
|
TrNode_child(parent_node) = child_node;
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
|
|
if (! IS_SUBGOAL_TRIE_HASH(child_node)) {
|
|
int count_nodes = 0;
|
|
do {
|
|
if (TrNode_entry(child_node) == t) {
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
count_nodes++;
|
|
child_node = TrNode_next(child_node);
|
|
} while (child_node);
|
|
NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, TrNode_child(parent_node));
|
|
count_nodes++;
|
|
if (count_nodes >= MAX_NODES_PER_TRIE_LEVEL) {
|
|
/* alloc a new hash */
|
|
sg_hash_ptr hash;
|
|
sg_node_ptr chain_node, next_node, *bucket;
|
|
new_subgoal_trie_hash(hash, count_nodes, tab_ent);
|
|
chain_node = child_node;
|
|
do {
|
|
bucket = Hash_bucket(hash, HASH_ENTRY(TrNode_entry(chain_node), BASE_HASH_BUCKETS - 1));
|
|
next_node = TrNode_next(chain_node);
|
|
TrNode_next(chain_node) = *bucket;
|
|
*bucket = chain_node;
|
|
chain_node = next_node;
|
|
} while (chain_node);
|
|
TrNode_child(parent_node) = (sg_node_ptr) hash;
|
|
} else {
|
|
TrNode_child(parent_node) = child_node;
|
|
}
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
|
|
{ /* trie nodes with hashing */
|
|
sg_hash_ptr hash;
|
|
sg_node_ptr *bucket;
|
|
int count_nodes = 0;
|
|
hash = (sg_hash_ptr) child_node;
|
|
bucket = Hash_bucket(hash, HASH_ENTRY(t, Hash_seed(hash)));
|
|
child_node = *bucket;
|
|
while (child_node) {
|
|
if (TrNode_entry(child_node) == t) {
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
count_nodes++;
|
|
child_node = TrNode_next(child_node);
|
|
}
|
|
NEW_SUBGOAL_TRIE_NODE(child_node, t, NULL, parent_node, *bucket);
|
|
*bucket = child_node;
|
|
Hash_num_nodes(hash)++;
|
|
count_nodes++;
|
|
if (count_nodes >= MAX_NODES_PER_BUCKET && Hash_num_nodes(hash) > Hash_num_buckets(hash)) {
|
|
/* expand current hash */
|
|
sg_node_ptr chain_node, next_node, *first_old_bucket, *old_bucket;
|
|
int seed;
|
|
first_old_bucket = Hash_buckets(hash);
|
|
old_bucket = first_old_bucket + Hash_num_buckets(hash);
|
|
Hash_num_buckets(hash) *= 2;
|
|
ALLOC_HASH_BUCKETS(Hash_buckets(hash), Hash_num_buckets(hash));
|
|
seed = Hash_seed(hash);
|
|
do {
|
|
if (*--old_bucket) {
|
|
chain_node = *old_bucket;
|
|
do {
|
|
bucket = Hash_bucket(hash, HASH_ENTRY(TrNode_entry(chain_node), seed));
|
|
next_node = TrNode_next(chain_node);
|
|
TrNode_next(chain_node) = *bucket;
|
|
*bucket = chain_node;
|
|
chain_node = next_node;
|
|
} while (chain_node);
|
|
}
|
|
} while (old_bucket != first_old_bucket);
|
|
FREE_HASH_BUCKETS(first_old_bucket);
|
|
}
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
}
|
|
#endif /* TABLE_LOCK_LEVEL */
|
|
#endif /* INCLUDE_SUBGOAL_TRIE_CHECK_INSERT */
|
|
|
|
|
|
|
|
/************************************************************************
|
|
** answer_trie_check_insert_(gt)_token **
|
|
************************************************************************/
|
|
|
|
#ifdef INCLUDE_ANSWER_TRIE_CHECK_INSERT
|
|
#ifdef TABLE_LOCK_AT_WRITE_LEVEL
|
|
#ifdef IS_GLOBAL_TRIE_REFERENCE
|
|
static inline ans_node_ptr answer_trie_check_insert_gt_token(sg_fr_ptr sg_fr, ans_node_ptr parent_node, Term t, int instr) {
|
|
#else
|
|
static inline ans_node_ptr answer_trie_check_insert_token(sg_fr_ptr sg_fr, ans_node_ptr parent_node, Term t, int instr) {
|
|
#endif /* IS_GLOBAL_TRIE_REFERENCE */
|
|
ans_node_ptr child_node;
|
|
ans_hash_ptr hash;
|
|
|
|
#ifdef TABLING_ERRORS
|
|
if (IS_ANSWER_LEAF_NODE(parent_node))
|
|
TABLING_ERROR_MESSAGE("IS_ANSWER_LEAF_NODE(parent_node) (answer_token_check_insert)");
|
|
#endif /* TABLING_ERRORS */
|
|
|
|
child_node = TrNode_child(parent_node);
|
|
if (child_node == NULL) {
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, NULL);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
LOCK_NODE(parent_node);
|
|
if (TrNode_child(parent_node)) {
|
|
ans_node_ptr chain_node = TrNode_child(parent_node);
|
|
if (IS_ANSWER_TRIE_HASH(chain_node)) {
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
FREE_ANSWER_TRIE_NODE(child_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
UNLOCK_NODE(parent_node);
|
|
hash = (ans_hash_ptr) chain_node;
|
|
goto answer_trie_hash;
|
|
}
|
|
do {
|
|
if (TrNode_entry(chain_node) == t) {
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
FREE_ANSWER_TRIE_NODE(child_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
UNLOCK_NODE(parent_node);
|
|
return chain_node;
|
|
}
|
|
chain_node = TrNode_next(chain_node);
|
|
} while (chain_node);
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
TrNode_next(child_node) = TrNode_child(parent_node);
|
|
#else
|
|
NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, TrNode_child(parent_node));
|
|
} else {
|
|
NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, NULL);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
}
|
|
TrNode_child(parent_node) = child_node;
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
|
|
if (! IS_ANSWER_TRIE_HASH(child_node)) {
|
|
ans_node_ptr first_node = child_node;
|
|
int count_nodes = 0;
|
|
do {
|
|
if (TrNode_entry(child_node) == t) {
|
|
return child_node;
|
|
}
|
|
count_nodes++;
|
|
child_node = TrNode_next(child_node);
|
|
} while (child_node);
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, first_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
LOCK_NODE(parent_node);
|
|
if (first_node != TrNode_child(parent_node)) {
|
|
ans_node_ptr chain_node = TrNode_child(parent_node);
|
|
if (IS_ANSWER_TRIE_HASH(chain_node)) {
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
FREE_ANSWER_TRIE_NODE(child_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
UNLOCK_NODE(parent_node);
|
|
hash = (ans_hash_ptr) chain_node;
|
|
goto answer_trie_hash;
|
|
}
|
|
do {
|
|
if (TrNode_entry(chain_node) == t) {
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
FREE_ANSWER_TRIE_NODE(child_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
UNLOCK_NODE(parent_node);
|
|
return chain_node;
|
|
}
|
|
count_nodes++;
|
|
chain_node = TrNode_next(chain_node);
|
|
} while (chain_node != first_node);
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
TrNode_next(child_node) = TrNode_child(parent_node);
|
|
#else
|
|
NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, TrNode_child(parent_node));
|
|
} else {
|
|
NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, first_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
}
|
|
count_nodes++;
|
|
if (count_nodes >= MAX_NODES_PER_TRIE_LEVEL) {
|
|
/* alloc a new hash */
|
|
ans_node_ptr chain_node, next_node, *bucket;
|
|
new_answer_trie_hash(hash, count_nodes, sg_fr);
|
|
chain_node = child_node;
|
|
do {
|
|
bucket = Hash_bucket(hash, HASH_ENTRY(TrNode_entry(chain_node), BASE_HASH_BUCKETS - 1));
|
|
next_node = TrNode_next(chain_node);
|
|
TrNode_next(chain_node) = *bucket;
|
|
*bucket = chain_node;
|
|
chain_node = next_node;
|
|
} while (chain_node);
|
|
TrNode_child(parent_node) = (ans_node_ptr) hash;
|
|
} else {
|
|
TrNode_child(parent_node) = child_node;
|
|
}
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
|
|
hash = (ans_hash_ptr) child_node;
|
|
answer_trie_hash:
|
|
{ /* trie nodes with hashing */
|
|
ans_node_ptr *bucket, first_node;
|
|
int seed, count_nodes = 0;
|
|
|
|
seed = Hash_seed(hash);
|
|
bucket = Hash_bucket(hash, HASH_ENTRY(t, seed));
|
|
first_node = child_node = *bucket;
|
|
while (child_node) {
|
|
if (TrNode_entry(child_node) == t) {
|
|
return child_node;
|
|
}
|
|
count_nodes++;
|
|
child_node = TrNode_next(child_node);
|
|
}
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, first_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
LOCK_NODE(parent_node);
|
|
if (seed != Hash_seed(hash)) {
|
|
/* the hash has been expanded */
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
FREE_ANSWER_TRIE_NODE(child_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
UNLOCK_NODE(parent_node);
|
|
goto answer_trie_hash;
|
|
}
|
|
if (first_node != *bucket) {
|
|
ans_node_ptr chain_node = *bucket;
|
|
do {
|
|
if (TrNode_entry(chain_node) == t) {
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
FREE_ANSWER_TRIE_NODE(child_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
UNLOCK_NODE(parent_node);
|
|
return chain_node;
|
|
}
|
|
count_nodes++;
|
|
chain_node = TrNode_next(chain_node);
|
|
} while (chain_node != first_node);
|
|
#ifdef ALLOC_BEFORE_CHECK
|
|
TrNode_next(child_node) = *bucket;
|
|
#else
|
|
NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, *bucket);
|
|
} else {
|
|
NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, first_node);
|
|
#endif /* ALLOC_BEFORE_CHECK */
|
|
}
|
|
*bucket = child_node;
|
|
Hash_num_nodes(hash)++;
|
|
count_nodes++;
|
|
if (count_nodes >= MAX_NODES_PER_BUCKET && Hash_num_nodes(hash) > Hash_num_buckets(hash)) {
|
|
/* expand current hash */
|
|
ans_node_ptr chain_node, next_node, *first_old_bucket, *old_bucket;
|
|
first_old_bucket = Hash_buckets(hash);
|
|
old_bucket = first_old_bucket + Hash_num_buckets(hash);
|
|
Hash_num_buckets(hash) *= 2;
|
|
ALLOC_HASH_BUCKETS(Hash_buckets(hash), Hash_num_buckets(hash));
|
|
seed = Hash_seed(hash);
|
|
do {
|
|
if (*--old_bucket) {
|
|
chain_node = *old_bucket;
|
|
do {
|
|
bucket = Hash_bucket(hash, HASH_ENTRY(TrNode_entry(chain_node), seed));
|
|
next_node = TrNode_next(chain_node);
|
|
TrNode_next(chain_node) = *bucket;
|
|
*bucket = chain_node;
|
|
chain_node = next_node;
|
|
} while (chain_node);
|
|
}
|
|
} while (old_bucket != first_old_bucket);
|
|
FREE_HASH_BUCKETS(first_old_bucket);
|
|
}
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
}
|
|
#else /* TABLE_LOCK_AT_ENTRY_LEVEL || TABLE_LOCK_AT_NODE_LEVEL || ! YAPOR */
|
|
#ifdef IS_GLOBAL_TRIE_REFERENCE
|
|
static inline ans_node_ptr answer_trie_check_insert_gt_token(sg_fr_ptr sg_fr, ans_node_ptr parent_node, Term t, int instr) {
|
|
#else
|
|
static inline ans_node_ptr answer_trie_check_insert_token(sg_fr_ptr sg_fr, ans_node_ptr parent_node, Term t, int instr) {
|
|
#endif /* IS_GLOBAL_TRIE_REFERENCE */
|
|
ans_node_ptr child_node;
|
|
|
|
#ifdef TABLING_ERRORS
|
|
if (IS_ANSWER_LEAF_NODE(parent_node))
|
|
TABLING_ERROR_MESSAGE("IS_ANSWER_LEAF_NODE(parent_node) (answer_token_check_insert)");
|
|
#endif /* TABLING_ERRORS */
|
|
|
|
LOCK_NODE(parent_node);
|
|
child_node = TrNode_child(parent_node);
|
|
if (child_node == NULL) {
|
|
NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, NULL);
|
|
TrNode_child(parent_node) = child_node;
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
|
|
if (! IS_ANSWER_TRIE_HASH(child_node)) {
|
|
int count_nodes = 0;
|
|
do {
|
|
if (TrNode_entry(child_node) == t) {
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
count_nodes++;
|
|
child_node = TrNode_next(child_node);
|
|
} while (child_node);
|
|
NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, TrNode_child(parent_node));
|
|
count_nodes++;
|
|
if (count_nodes >= MAX_NODES_PER_TRIE_LEVEL) {
|
|
/* alloc a new hash */
|
|
ans_hash_ptr hash;
|
|
ans_node_ptr chain_node, next_node, *bucket;
|
|
new_answer_trie_hash(hash, count_nodes, sg_fr);
|
|
chain_node = child_node;
|
|
do {
|
|
bucket = Hash_bucket(hash, HASH_ENTRY(TrNode_entry(chain_node), BASE_HASH_BUCKETS - 1));
|
|
next_node = TrNode_next(chain_node);
|
|
TrNode_next(chain_node) = *bucket;
|
|
*bucket = chain_node;
|
|
chain_node = next_node;
|
|
} while (chain_node);
|
|
TrNode_child(parent_node) = (ans_node_ptr) hash;
|
|
} else {
|
|
TrNode_child(parent_node) = child_node;
|
|
}
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
|
|
{ /* trie nodes with hashing */
|
|
ans_hash_ptr hash;
|
|
ans_node_ptr *bucket;
|
|
int count_nodes = 0;
|
|
hash = (ans_hash_ptr) child_node;
|
|
bucket = Hash_bucket(hash, HASH_ENTRY(t, Hash_seed(hash)));
|
|
child_node = *bucket;
|
|
while (child_node) {
|
|
if (TrNode_entry(child_node) == t) {
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
count_nodes++;
|
|
child_node = TrNode_next(child_node);
|
|
}
|
|
NEW_ANSWER_TRIE_NODE(child_node, instr, t, NULL, parent_node, *bucket);
|
|
*bucket = child_node;
|
|
Hash_num_nodes(hash)++;
|
|
count_nodes++;
|
|
if (count_nodes >= MAX_NODES_PER_BUCKET && Hash_num_nodes(hash) > Hash_num_buckets(hash)) {
|
|
/* expand current hash */
|
|
ans_node_ptr chain_node, next_node, *first_old_bucket, *old_bucket;
|
|
int seed;
|
|
first_old_bucket = Hash_buckets(hash);
|
|
old_bucket = first_old_bucket + Hash_num_buckets(hash);
|
|
Hash_num_buckets(hash) *= 2;
|
|
ALLOC_HASH_BUCKETS(Hash_buckets(hash), Hash_num_buckets(hash));
|
|
seed = Hash_seed(hash);
|
|
do {
|
|
if (*--old_bucket) {
|
|
chain_node = *old_bucket;
|
|
do {
|
|
bucket = Hash_bucket(hash, HASH_ENTRY(TrNode_entry(chain_node), seed));
|
|
next_node = TrNode_next(chain_node);
|
|
TrNode_next(chain_node) = *bucket;
|
|
*bucket = chain_node;
|
|
chain_node = next_node;
|
|
} while (chain_node);
|
|
}
|
|
} while (old_bucket != first_old_bucket);
|
|
FREE_HASH_BUCKETS(first_old_bucket);
|
|
}
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
}
|
|
#endif /* TABLE_LOCK_LEVEL */
|
|
#endif /* INCLUDE_ANSWER_TRIE_CHECK_INSERT */
|
|
|
|
|
|
|
|
/************************************************************************
|
|
** global_trie_check_insert_(gt)_token **
|
|
************************************************************************/
|
|
|
|
#ifdef INCLUDE_GLOBAL_TRIE_CHECK_INSERT
|
|
#ifdef IS_GLOBAL_TRIE_REFERENCE
|
|
static inline gt_node_ptr global_trie_check_insert_gt_token(gt_node_ptr parent_node, Term t) {
|
|
#else
|
|
static inline gt_node_ptr global_trie_check_insert_token(gt_node_ptr parent_node, Term t) {
|
|
#endif /* IS_GLOBAL_TRIE_REFERENCE */
|
|
gt_node_ptr child_node;
|
|
|
|
LOCK_NODE(parent_node);
|
|
child_node = TrNode_child(parent_node);
|
|
if (child_node == NULL) {
|
|
NEW_GLOBAL_TRIE_NODE(child_node, t, NULL, parent_node, NULL);
|
|
TrNode_child(parent_node) = child_node;
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
|
|
if (! IS_GLOBAL_TRIE_HASH(child_node)) {
|
|
int count_nodes = 0;
|
|
do {
|
|
if (TrNode_entry(child_node) == t) {
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
count_nodes++;
|
|
child_node = TrNode_next(child_node);
|
|
} while (child_node);
|
|
NEW_GLOBAL_TRIE_NODE(child_node, t, NULL, parent_node, TrNode_child(parent_node));
|
|
count_nodes++;
|
|
if (count_nodes >= MAX_NODES_PER_TRIE_LEVEL) {
|
|
/* alloc a new hash */
|
|
gt_hash_ptr hash;
|
|
gt_node_ptr chain_node, next_node, *bucket;
|
|
new_global_trie_hash(hash, count_nodes);
|
|
chain_node = child_node;
|
|
do {
|
|
bucket = Hash_bucket(hash, HASH_ENTRY(TrNode_entry(chain_node), BASE_HASH_BUCKETS - 1));
|
|
next_node = TrNode_next(chain_node);
|
|
TrNode_next(chain_node) = *bucket;
|
|
*bucket = chain_node;
|
|
chain_node = next_node;
|
|
} while (chain_node);
|
|
TrNode_child(parent_node) = (gt_node_ptr) hash;
|
|
} else {
|
|
TrNode_child(parent_node) = child_node;
|
|
}
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
|
|
{ /* trie nodes with hashing */
|
|
gt_hash_ptr hash;
|
|
gt_node_ptr *bucket;
|
|
int count_nodes = 0;
|
|
hash = (gt_hash_ptr) child_node;
|
|
bucket = Hash_bucket(hash, HASH_ENTRY(t, Hash_seed(hash)));
|
|
child_node = *bucket;
|
|
while (child_node) {
|
|
if (TrNode_entry(child_node) == t) {
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
count_nodes++;
|
|
child_node = TrNode_next(child_node);
|
|
}
|
|
NEW_GLOBAL_TRIE_NODE(child_node, t, NULL, parent_node, *bucket);
|
|
*bucket = child_node;
|
|
Hash_num_nodes(hash)++;
|
|
count_nodes++;
|
|
if (count_nodes >= MAX_NODES_PER_BUCKET && Hash_num_nodes(hash) > Hash_num_buckets(hash)) {
|
|
/* expand current hash */
|
|
gt_node_ptr chain_node, next_node, *first_old_bucket, *old_bucket;
|
|
int seed;
|
|
first_old_bucket = Hash_buckets(hash);
|
|
old_bucket = first_old_bucket + Hash_num_buckets(hash);
|
|
Hash_num_buckets(hash) *= 2;
|
|
ALLOC_HASH_BUCKETS(Hash_buckets(hash), Hash_num_buckets(hash));
|
|
seed = Hash_seed(hash);
|
|
do {
|
|
if (*--old_bucket) {
|
|
chain_node = *old_bucket;
|
|
do {
|
|
bucket = Hash_bucket(hash, HASH_ENTRY(TrNode_entry(chain_node), seed));
|
|
next_node = TrNode_next(chain_node);
|
|
TrNode_next(chain_node) = *bucket;
|
|
*bucket = chain_node;
|
|
chain_node = next_node;
|
|
} while (chain_node);
|
|
}
|
|
} while (old_bucket != first_old_bucket);
|
|
FREE_HASH_BUCKETS(first_old_bucket);
|
|
}
|
|
UNLOCK_NODE(parent_node);
|
|
return child_node;
|
|
}
|
|
}
|
|
#endif /* INCLUDE_GLOBAL_TRIE_CHECK_INSERT */
|