:- module table_builtin.
:- use_module builtin, io, private_builtin, require.
:- pragma foreign_import_module("C", table_builtin).
:- semipure pred table_builtin:table_nondet_return_all_ans_2((builtin:c_pointer), (builtin:c_pointer)).
:- mode table_builtin:table_nondet_return_all_ans_2((builtin:in), (builtin:out)) is nondet.
:- semipure pred table_builtin:pickup_answer_list((builtin:c_pointer), (builtin:c_pointer)).
:- mode table_builtin:pickup_answer_list((builtin:in), (builtin:out)) is det.
:- pragma promise_semipure((table_builtin:pickup_answer_list)/2).
:- semipure pred table_builtin:return_next_answer((builtin:c_pointer), (builtin:c_pointer), (builtin:c_pointer)).
:- mode table_builtin:return_next_answer((builtin:in), (builtin:out), (builtin:out)) is semidet.
:- pragma promise_semipure((table_builtin:return_next_answer)/3).
:- pragma promise_semipure((table_builtin:table_simple_is_complete)/1).
:- pragma foreign_proc("C", table_builtin:table_simple_is_complete(T :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;

#ifdef	MR_TABLE_DEBUG
	if (MR_tabledebug) {
		printf(\"checking if simple %p is complete: %ld (%lx)\\n\",
			table, (long) table->MR_simpletable_status,
			(long) table->MR_simpletable_status);
	}
#endif
	SUCCESS_INDICATOR = 
		((table->MR_simpletable_status == MR_SIMPLETABLE_FAILED)
		|| (table->MR_simpletable_status >= MR_SIMPLETABLE_SUCCEEDED));
").
:- pragma promise_semipure((table_builtin:table_simple_has_succeeded)/1).
:- pragma foreign_proc("C", table_builtin:table_simple_has_succeeded(T :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;

#ifdef	MR_TABLE_DEBUG
	if (MR_tabledebug) {
		printf(\"checking if simple %p is succeeded: %ld (%lx)\\n\",
			table, (long) table->MR_simpletable_status,
			(long) table->MR_simpletable_status);
	}
#endif
	SUCCESS_INDICATOR =
		(table->MR_simpletable_status >= MR_SIMPLETABLE_SUCCEEDED);
").
:- pragma promise_semipure((table_builtin:table_simple_has_failed)/1).
:- pragma foreign_proc("C", table_builtin:table_simple_has_failed(T :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;

#ifdef	MR_TABLE_DEBUG
	if (MR_tabledebug) {
		printf(\"checking if simple %p is failed: %ld (%lx)\\n\",
			table, (long) table->MR_simpletable_status,
			(long) table->MR_simpletable_status);
	}
#endif
	SUCCESS_INDICATOR =
		(table->MR_simpletable_status == MR_SIMPLETABLE_FAILED);
").
:- pragma promise_semipure((table_builtin:table_simple_is_active)/1).
:- pragma foreign_proc("C", table_builtin:table_simple_is_active(T :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;

#ifdef	MR_TABLE_DEBUG
	if (MR_tabledebug) {
		printf(\"checking if simple %p is active: %ld (%lx)\\n\",
			table, (long) table->MR_simpletable_status,
			(long) table->MR_simpletable_status);
	}
#endif
	SUCCESS_INDICATOR =
		(table->MR_simpletable_status == MR_SIMPLETABLE_WORKING);
").
:- pragma promise_semipure((table_builtin:table_simple_is_inactive)/1).
:- pragma foreign_proc("C", table_builtin:table_simple_is_inactive(T :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;

#ifdef	MR_TABLE_DEBUG
	if (MR_tabledebug) {
		printf(\"checking if simple %p is inactive: %ld (%lx)\\n\",
			table, (long) table->MR_simpletable_status,
			(long) table->MR_simpletable_status);
	}
#endif
	SUCCESS_INDICATOR =
		(table->MR_simpletable_status != MR_SIMPLETABLE_WORKING);
").
:- pragma foreign_proc("C", table_builtin:table_simple_mark_as_succeeded(T :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;

#ifdef	MR_TABLE_DEBUG
	if (MR_tabledebug) {
		printf(\"marking %p as succeeded\\n\", table);
	}
#endif
	table->MR_simpletable_status = MR_SIMPLETABLE_SUCCEEDED;
").
:- pragma foreign_proc("C", table_builtin:table_simple_mark_as_failed(T :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;

#ifdef	MR_TABLE_DEBUG
	if (MR_tabledebug) {
		printf(\"marking %p as failed\\n\", table);
	}
#endif
	table->MR_simpletable_status = MR_SIMPLETABLE_FAILED;
").
:- pragma foreign_proc("C", table_builtin:table_simple_mark_as_active(T :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;

#ifdef	MR_TABLE_DEBUG
	if (MR_tabledebug) {
		printf(\"marking %p as working\\n\", table);
	}
#endif
	table->MR_simpletable_status = MR_SIMPLETABLE_WORKING;
").
:- pragma foreign_proc("C", table_builtin:table_simple_mark_as_inactive(T :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;

#ifdef	MR_TABLE_DEBUG
	if (MR_tabledebug) {
		printf(\"marking %p as uninitialized\\n\", table);
	}
#endif
	table->MR_simpletable_status = MR_SIMPLETABLE_UNINITIALIZED;
").
:- pragma foreign_proc("C", table_builtin:table_io_in_range(T :: (builtin:out), Counter :: (builtin:out), Start :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	if (MR_io_tabling_enabled) {
		MR_Unsigned	old_counter;

#ifdef	MR_DEBUG_RETRY
		if (MR_io_tabling_debug) {
			printf(\"checking table_io_in_range: \"
				\"prev %d, start %d, hwm %d\",
				MR_io_tabling_counter, MR_io_tabling_start,
				MR_io_tabling_counter_hwm);
		}
#endif

		old_counter = MR_io_tabling_counter;

		MR_io_tabling_counter++;

		if (MR_io_tabling_start < MR_io_tabling_counter 
			&& MR_io_tabling_counter <= MR_io_tabling_end)
		{
			T = (MR_Word) &MR_io_tabling_pointer;
			Counter = (MR_Word) old_counter;
			Start = MR_io_tabling_start;
			if (MR_io_tabling_counter > MR_io_tabling_counter_hwm)
			{
				MR_io_tabling_counter_hwm =
					MR_io_tabling_counter;
			}

#ifdef	MR_DEBUG_RETRY
			if (MR_io_tabling_debug) {
				printf(\" in range
\");
			}
#endif

			SUCCESS_INDICATOR = MR_TRUE;
		} else {

#ifdef	MR_DEBUG_RETRY
			if (MR_io_tabling_debug) {
				printf(\" not in range
\");
			}
#endif
			SUCCESS_INDICATOR = MR_FALSE;
		}
	} else {
		SUCCESS_INDICATOR = MR_FALSE;
	}
").
:- pragma foreign_proc("C", table_builtin:table_io_has_occurred(T :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;

#ifdef	MR_TABLE_DEBUG
	if (MR_tabledebug) {
		printf(\"checking %p for previous execution: %p\\n\",
			table, table->MR_answerblock);
	}
#endif
	SUCCESS_INDICATOR = (table->MR_answerblock != NULL);
").
table_builtin:table_io_copy_io_state(IO_3, IO_3).
:- pragma foreign_proc("C", table_builtin:table_io_left_bracket_unitized_goal(TraceEnabled :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	TraceEnabled = MR_trace_enabled;
	MR_trace_enabled = MR_FALSE;
	MR_io_tabling_enabled = MR_FALSE;
").
:- pragma foreign_proc("C", table_builtin:table_io_right_bracket_unitized_goal(TraceEnabled :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_io_tabling_enabled = MR_TRUE;
	MR_trace_enabled = TraceEnabled;
").
:- pragma foreign_proc("C", table_builtin:table_nondet_setup(T0 :: (builtin:in), T :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
#ifndef	MR_USE_MINIMAL_MODEL
	MR_fatal_error(\"minimal model code entered when not enabled\");
#else
#ifdef	MR_THREAD_SAFE
#error \"Sorry, not yet implemented: mixing minimal model tabling and threads\"
#endif
	MR_TrieNode	table;

	table = (MR_TrieNode) T0;

	/*
	** Initialize the subgoal if this is the first time we see it.
	** If the subgoal structure already exists but is marked inactive,
	** then it was left by a previous generator that couldn\'t
	** complete the evaluation of the subgoal due to a commit.
	** In that case, we want to forget all about the old generator.
	*/

	if (table->MR_subgoal == NULL) {
		MR_Subgoal	*subgoal;

		subgoal = MR_TABLE_NEW(MR_Subgoal);

		subgoal->status = MR_SUBGOAL_INACTIVE;
		subgoal->leader = NULL;
		subgoal->followers = MR_TABLE_NEW(MR_SubgoalListNode);
		subgoal->followers->item = subgoal;
		subgoal->followers->next = NULL;
		subgoal->followers_tail = &(subgoal->followers->next);
		subgoal->answer_table = (MR_Word) NULL;
		subgoal->num_ans = 0;
		subgoal->answer_list = NULL;
		subgoal->answer_list_tail = &subgoal->answer_list;
		subgoal->consumer_list = NULL;
		subgoal->consumer_list_tail = &subgoal->consumer_list;

#ifdef	MR_TABLE_DEBUG
		if (MR_tabledebug) {
			printf(\"setting up table %p -> %p, answer slot %p\\n\",
				table, subgoal, subgoal->answer_list_tail);
		}

		if (MR_maxfr != MR_curfr) {
			MR_fatal_error(
				\"MR_maxfr != MR_curfr at table setup\\n\");
		}
#endif
#ifdef MR_HIGHLEVEL_CODE
 		MR_fatal_error(\"sorry, not implemented: \"
			\"minimal_model tabling with --high-level-code\");
#else
		subgoal->generator_maxfr = MR_prevfr_slot(MR_maxfr);
		subgoal->generator_sp = MR_sp;
#endif
		table->MR_subgoal = subgoal;
	}
	T = T0;
#endif /* MR_USE_MINIMAL_MODEL */
").
:- pragma promise_semipure((table_builtin:table_nondet_is_complete)/1).
:- pragma foreign_proc("C", table_builtin:table_nondet_is_complete(T :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
#ifdef	MR_USE_MINIMAL_MODEL
	MR_TrieNode	table;

	table = (MR_TrieNode) T;

	SUCCESS_INDICATOR = (table->MR_subgoal->status == MR_SUBGOAL_COMPLETE);
#else
	MR_fatal_error(\"minimal model code entered when not enabled\");
#endif
").
:- pragma promise_semipure((table_builtin:table_nondet_is_active)/1).
:- pragma foreign_proc("C", table_builtin:table_nondet_is_active(T :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
#ifdef	MR_USE_MINIMAL_MODEL
	MR_TrieNode	table;

	table = (MR_TrieNode) T;

	SUCCESS_INDICATOR = (table->MR_subgoal->status == MR_SUBGOAL_ACTIVE);
#else
	MR_fatal_error(\"minimal model code entered when not enabled\");
#endif
").
:- pragma foreign_proc("C", table_builtin:table_nondet_mark_as_active(T :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
#ifdef	MR_USE_MINIMAL_MODEL
	MR_TrieNode	table;

	table = (MR_TrieNode) T;

	MR_push_generator(MR_curfr, table);
	MR_register_generator_ptr(table);
	table->MR_subgoal->status = MR_SUBGOAL_ACTIVE;
#else
	MR_fatal_error(\"minimal model code entered when not enabled\");
#endif
").
:- pragma foreign_proc("C", table_builtin:table_nondet_get_ans_table(T :: (builtin:in), AT :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
#ifdef	MR_USE_MINIMAL_MODEL
	MR_TrieNode	table;

	table = (MR_TrieNode) T;

	AT = (MR_Word) &(table->MR_subgoal->answer_table);
#else
	MR_fatal_error(\"minimal model code entered when not enabled\");
#endif
").
:- pragma foreign_proc("C", table_builtin:table_nondet_answer_is_not_duplicate(T :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
#ifndef	MR_USE_MINIMAL_MODEL
	MR_fatal_error(\"minimal model code entered when not enabled\");
#else
	MR_TrieNode	table;
	MR_bool		is_new_answer;

	table = (MR_TrieNode) T;

#ifdef	MR_TABLE_DEBUG
	if (MR_tabledebug) {
		printf(\"checking if %p is a duplicate answer: %ld\\n\",
			table, (long) table->MR_integer);
	}
#endif

	is_new_answer = (table->MR_integer == 0);
	table->MR_integer = 1;	/* any nonzero value will do */
	SUCCESS_INDICATOR = is_new_answer;
#endif
").
:- pragma foreign_proc("C", table_builtin:table_nondet_new_ans_slot(T :: (builtin:in), Slot :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
#ifndef	MR_USE_MINIMAL_MODEL
	MR_fatal_error(\"minimal model code entered when not enabled\");
#else
	MR_TrieNode		table;
	MR_Subgoal		*subgoal;
	MR_AnswerListNode	*answer_node;

	table = (MR_TrieNode) T;
	subgoal = table->MR_subgoal;
	subgoal->num_ans++;

	/*
	**
	** We fill in the answer_data slot with a dummy value.
	** This slot will be filled in by the next piece of code
	** to be executed after we return, which is why we return its address.
	*/

	answer_node = MR_TABLE_NEW(MR_AnswerListNode);
	answer_node->answer_num = subgoal->num_ans;
	answer_node->answer_data.MR_integer = 0;
	answer_node->next_answer = NULL;

#ifdef	MR_TABLE_DEBUG
	if (MR_tabledebug) {
		printf(\"new answer slot %d at %p(%p), storing into %p\\n\",
			subgoal->num_ans, answer_node,
			&answer_node->answer_data, subgoal->answer_list_tail);
	}
#endif

	*(subgoal->answer_list_tail) = answer_node;
	subgoal->answer_list_tail = &(answer_node->next_answer);

	Slot = (MR_Word) &(answer_node->answer_data);
#endif
").
table_builtin:table_nondet_return_all_ans(TrieNode_3, Answer_4) :-
		semipure table_builtin:pickup_answer_list(TrieNode_3, CurNode0_5),
		semipure table_builtin:table_nondet_return_all_ans_2(CurNode0_5, Answer_4).
table_builtin:table_nondet_return_all_ans_2(CurNode0_3, Answer_4) :-
		semipure table_builtin:return_next_answer(CurNode0_3, FirstAnswer_5, CurNode1_6),
		( % disjunction
			Answer_4 = FirstAnswer_5
		;
			semipure table_builtin:table_nondet_return_all_ans_2(CurNode1_6, Answer_4)
		).
:- pragma promise_semipure((table_builtin:pickup_answer_list)/2).
:- pragma foreign_proc("C", table_builtin:pickup_answer_list(T :: (builtin:in), CurNode :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
#ifdef MR_USE_MINIMAL_MODEL
		MR_TrieNode	table;

		table = (MR_TrieNode) T;
	CurNode = (MR_Word) table->MR_subgoal->answer_list;

  #ifdef MR_TABLE_DEBUG
		if (MR_tabledebug) {
			printf(\"restoring all answers in %p -> %p\\n\",
				table, table->MR_subgoal);
		}
  #endif
#endif
").
:- pragma promise_semipure((table_builtin:return_next_answer)/3).
:- pragma foreign_proc("C", table_builtin:return_next_answer(CurNode0 :: (builtin:in), AnswerBlock :: (builtin:out), CurNode :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
#ifdef MR_USE_MINIMAL_MODEL
	MR_AnswerList	cur_node0;

	cur_node0 = (MR_AnswerList *) CurNode0;
	if (cur_node0 == NULL) {
		SUCCESS_INDICATOR = MR_FALSE;
		} else {
		AnswerBlock = (MR_Word) &cur_node0->answer_data;
		CurNode = (MR_Word) cur_node0->next_answer;
		SUCCESS_INDICATOR = MR_TRUE;
		}
#else
		MR_fatal_error(\"minimal model code entered when not enabled\");
#endif
").
:- pragma foreign_proc("C", table_builtin:table_lookup_insert_int(T0 :: (builtin:in), I :: (builtin:in), T :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table0, table;

	table0 = (MR_TrieNode) T0;
	MR_DEBUG_NEW_TABLE_INT(table, table0, (MR_Integer) I);
	T = (MR_Word) table;
").
:- pragma foreign_proc("C", table_builtin:table_lookup_insert_start_int(T0 :: (builtin:in), S :: (builtin:in), I :: (builtin:in), T :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table0, table;

	table0 = (MR_TrieNode) T0;
	MR_DEBUG_NEW_TABLE_START_INT(table, table0,
		(MR_Integer) S, (MR_Integer) I);
	T = (MR_Word) table;
").
:- pragma foreign_proc("C", table_builtin:table_lookup_insert_char(T0 :: (builtin:in), C :: (builtin:in), T :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table0, table;

	table0 = (MR_TrieNode) T0;
	MR_DEBUG_NEW_TABLE_CHAR(table, table0, (MR_Integer) C);
	T = (MR_Word) table;
").
:- pragma foreign_proc("C", table_builtin:table_lookup_insert_string(T0 :: (builtin:in), S :: (builtin:in), T :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table0, table;

	table0 = (MR_TrieNode) T0;
	MR_DEBUG_NEW_TABLE_STRING(table, table0, (MR_String) S);
	T = (MR_Word) table;
").
:- pragma foreign_proc("C", table_builtin:table_lookup_insert_float(T0 :: (builtin:in), F :: (builtin:in), T :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table0, table;

	table0 = (MR_TrieNode) T0;
	MR_DEBUG_NEW_TABLE_FLOAT(table, table0, F);
	T = (MR_Word) table;
").
:- pragma foreign_proc("C", table_builtin:table_lookup_insert_enum(T0 :: (builtin:in), R :: (builtin:in), V :: (builtin:in), T :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table0, table;

	table0 = (MR_TrieNode) T0;
	MR_DEBUG_NEW_TABLE_ENUM(table, table0, R, V);
	T = (MR_Word) table;
").
:- pragma foreign_proc("C", table_builtin:table_lookup_insert_user(T0 :: (builtin:in), V :: (builtin:in), T :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table0, table;

	table0 = (MR_TrieNode) T0;
	MR_DEBUG_NEW_TABLE_ANY(table, table0, (MR_TypeInfo) TypeInfo_for_T, V);
	T = (MR_Word) table;
").
:- pragma foreign_proc("C", table_builtin:table_lookup_insert_poly(T0 :: (builtin:in), V :: (builtin:in), T :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table0, table;

	table0 = (MR_TrieNode) T0;
	MR_DEBUG_NEW_TABLE_ANY(table, table0, (MR_TypeInfo) TypeInfo_for_T, V);
	T = (MR_Word) table;
").
:- pragma foreign_proc("C", table_builtin:table_save_int_ans(T :: (builtin:in), Offset :: (builtin:in), I :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;
	MR_TABLE_SAVE_ANSWER(table, Offset, I,
		&MR_TYPE_CTOR_INFO_NAME(builtin, int, 0));
").
:- pragma foreign_proc("C", table_builtin:table_save_char_ans(T :: (builtin:in), Offset :: (builtin:in), C :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;
	MR_TABLE_SAVE_ANSWER(table, Offset, C,
		&MR_TYPE_CTOR_INFO_NAME(builtin, character, 0));
").
:- pragma foreign_proc("C", table_builtin:table_save_string_ans(T :: (builtin:in), Offset :: (builtin:in), S :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;
	MR_TABLE_SAVE_ANSWER(table, Offset, (MR_Word) S,
		&MR_TYPE_CTOR_INFO_NAME(builtin, string, 0));
").
:- pragma foreign_proc("C", table_builtin:table_save_float_ans(T :: (builtin:in), Offset :: (builtin:in), F :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;
#ifdef MR_HIGHLEVEL_CODE
	MR_TABLE_SAVE_ANSWER(table, Offset, (MR_Word) MR_box_float(F),
		&MR_TYPE_CTOR_INFO_NAME(builtin, float, 0));
#else
	MR_TABLE_SAVE_ANSWER(table, Offset, MR_float_to_word(F),
		&MR_TYPE_CTOR_INFO_NAME(builtin, float, 0));
#endif
").
:- pragma foreign_proc("C", table_builtin:table_save_io_state_ans(T :: (builtin:in), Offset :: (builtin:in), S :: (builtin:ui)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;
	MR_TABLE_SAVE_ANSWER(table, Offset, (MR_Word) S,
		&MR_TYPE_CTOR_INFO_NAME(io, state, 0));
").
:- pragma foreign_proc("C", table_builtin:table_save_any_ans(T :: (builtin:in), Offset :: (builtin:in), V :: (builtin:in)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;
	MR_TABLE_SAVE_ANSWER(table, Offset, V, TypeInfo_for_T);
").
:- pragma promise_semipure((table_builtin:table_restore_int_ans)/3).
:- pragma foreign_proc("C", table_builtin:table_restore_int_ans(T :: (builtin:in), Offset :: (builtin:in), I :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io, promise_semipure], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;
	I = (MR_Integer) MR_TABLE_GET_ANSWER(table, Offset);
").
:- pragma promise_semipure((table_builtin:table_restore_char_ans)/3).
:- pragma foreign_proc("C", table_builtin:table_restore_char_ans(T :: (builtin:in), Offset :: (builtin:in), C :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io, promise_semipure], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;
	C = (MR_Char) MR_TABLE_GET_ANSWER(table, Offset);
").
:- pragma promise_semipure((table_builtin:table_restore_string_ans)/3).
:- pragma foreign_proc("C", table_builtin:table_restore_string_ans(T :: (builtin:in), Offset :: (builtin:in), S :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io, promise_semipure], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;
	S = (MR_String) MR_TABLE_GET_ANSWER(table, Offset);
").
:- pragma promise_semipure((table_builtin:table_restore_float_ans)/3).
:- pragma foreign_proc("C", table_builtin:table_restore_float_ans(T :: (builtin:in), Offset :: (builtin:in), F :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io, promise_semipure], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;
#ifdef MR_HIGHLEVEL_CODE
	F = MR_unbox_float(MR_TABLE_GET_ANSWER(table, Offset));
#else
	F = MR_word_to_float(MR_TABLE_GET_ANSWER(table, Offset));
#endif
").
:- pragma promise_semipure((table_builtin:table_restore_io_state_ans)/3).
:- pragma foreign_proc("C", table_builtin:table_restore_io_state_ans(T :: (builtin:in), Offset :: (builtin:in), V :: (builtin:uo)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io, promise_semipure], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;
	V = (MR_Word) MR_TABLE_GET_ANSWER(table, Offset);
").
:- pragma promise_semipure((table_builtin:table_restore_any_ans)/3).
:- pragma foreign_proc("C", table_builtin:table_restore_any_ans(T :: (builtin:in), Offset :: (builtin:in), V :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io, promise_semipure], "
	MR_TrieNode	table;

	table = (MR_TrieNode) T;
	V = (MR_Word) MR_TABLE_GET_ANSWER(table, Offset);
").
table_builtin:table_loopcheck_error(Message_2) :-
		require:error(Message_2).
:- pragma foreign_proc("C", table_builtin:table_create_ans_block(T0 :: (builtin:in), Size :: (builtin:in), T :: (builtin:out)), [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_TrieNode	table0;

	table0 = (MR_TrieNode) T0;
	MR_TABLE_CREATE_ANSWER_BLOCK(table0, Size);
	T = T0;
").
:- pragma foreign_proc("C", table_builtin:table_report_statistics, [will_not_call_mercury, not_thread_safe, not_tabled_for_io], "
	MR_table_report_statistics(stderr);
").
:- pragma termination_info(table_builtin:table_simple_is_complete((builtin:in)), finite(0, [no]), cannot_loop).
:- pragma termination_info(table_builtin:table_simple_has_succeeded((builtin:in)), finite(0, [no]), cannot_loop).
:- pragma termination_info(table_builtin:table_simple_has_failed((builtin:in)), finite(0, [no]), cannot_loop).
:- pragma termination_info(table_builtin:table_simple_is_active((builtin:in)), finite(0, [no]), cannot_loop).
:- pragma termination_info(table_builtin:table_simple_is_inactive((builtin:in)), finite(0, [no]), cannot_loop).
:- pragma termination_info(table_builtin:table_simple_mark_as_succeeded((builtin:in)), finite(0, [no]), cannot_loop).
:- pragma termination_info(table_builtin:table_simple_mark_as_failed((builtin:in)), finite(0, [no]), cannot_loop).
:- pragma termination_info(table_builtin:table_simple_mark_as_active((builtin:in)), finite(0, [no]), cannot_loop).
:- pragma termination_info(table_builtin:table_simple_mark_as_inactive((builtin:in)), finite(0, [no]), cannot_loop).
:- pragma termination_info(table_builtin:table_io_in_range((builtin:out), (builtin:out), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_io_has_occurred((builtin:in)), finite(0, [no]), cannot_loop).
:- pragma termination_info(table_builtin:table_io_copy_io_state((builtin:di), (builtin:uo)), finite(0, [yes, no]), cannot_loop).
:- pragma termination_info(table_builtin:table_io_left_bracket_unitized_goal((builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_io_right_bracket_unitized_goal((builtin:in)), finite(0, [no]), cannot_loop).
:- pragma termination_info(table_builtin:table_nondet_setup((builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_nondet_is_complete((builtin:in)), finite(0, [no]), cannot_loop).
:- pragma termination_info(table_builtin:table_nondet_is_active((builtin:in)), finite(0, [no]), cannot_loop).
:- pragma termination_info(table_builtin:table_nondet_mark_as_active((builtin:in)), finite(0, [no]), cannot_loop).
:- pragma termination_info(table_builtin:table_nondet_get_ans_table((builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_nondet_answer_is_not_duplicate((builtin:in)), finite(0, [no]), cannot_loop).
:- pragma termination_info(table_builtin:table_nondet_new_ans_slot((builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_nondet_return_all_ans((builtin:in), (builtin:out)), infinite, can_loop).
:- pragma termination_info(table_builtin:table_multi_return_all_ans((builtin:in), (builtin:out)), infinite, can_loop).
:- pragma termination_info(table_builtin:table_lookup_insert_int((builtin:in), (builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_lookup_insert_start_int((builtin:in), (builtin:in), (builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_lookup_insert_char((builtin:in), (builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_lookup_insert_string((builtin:in), (builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_lookup_insert_float((builtin:in), (builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_lookup_insert_enum((builtin:in), (builtin:in), (builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_lookup_insert_user((builtin:in), (builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_lookup_insert_poly((builtin:in), (builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_save_int_ans((builtin:in), (builtin:in), (builtin:in)), finite(0, [no, no, no]), cannot_loop).
:- pragma termination_info(table_builtin:table_save_char_ans((builtin:in), (builtin:in), (builtin:in)), finite(0, [no, no, no]), cannot_loop).
:- pragma termination_info(table_builtin:table_save_string_ans((builtin:in), (builtin:in), (builtin:in)), finite(0, [no, no, no]), cannot_loop).
:- pragma termination_info(table_builtin:table_save_float_ans((builtin:in), (builtin:in), (builtin:in)), finite(0, [no, no, no]), cannot_loop).
:- pragma termination_info(table_builtin:table_save_io_state_ans((builtin:in), (builtin:in), (builtin:ui)), finite(0, [no, no, no]), cannot_loop).
:- pragma termination_info(table_builtin:table_save_any_ans((builtin:in), (builtin:in), (builtin:in)), finite(0, [no, no, no, no]), cannot_loop).
:- pragma termination_info(table_builtin:table_restore_int_ans((builtin:in), (builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_restore_char_ans((builtin:in), (builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_restore_string_ans((builtin:in), (builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_restore_float_ans((builtin:in), (builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_restore_io_state_ans((builtin:in), (builtin:in), (builtin:uo)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_restore_any_ans((builtin:in), (builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info(table_builtin:table_loopcheck_error((builtin:in)), infinite, can_loop).
:- pragma termination_info(table_builtin:table_create_ans_block((builtin:in), (builtin:in), (builtin:out)), infinite, cannot_loop).
:- pragma termination_info((table_builtin:table_report_statistics), finite(0, []), cannot_loop).
