/*
** Copyright (C) 1997-2000,2002-2007 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/

/*
** mercury_tabling.h - definitions of some basic stuff used for tabling.
** For tabling code, the Mercury compiler (compiler/table_gen.m) generates
** references to special procedures defined in library/table_builtin.m.
** The types and macros defined here are used by the procedures defined in
** library/table_builtin.m.
*/

#ifndef	MERCURY_TABLING_H
#define	MERCURY_TABLING_H

#include "mercury_types.h"
#include "mercury_bitmap.h"
#include "mercury_type_info.h"
#include "mercury_float.h"
#include "mercury_reg_workarounds.h"
#include "mercury_dlist.h"
#include "mercury_goto.h"	/* for MR_declare_entry */
#include "mercury_tags.h"   	/* for `MR_DEFINE_BUILTIN_ENUM_CONST' */

#ifndef MR_CONSERVATIVE_GC
  #include "mercury_deep_copy.h"
#endif

#include <stdio.h>

#ifdef	MR_TABLE_DEBUG
#define	MR_TABLE_DEBUG_BOOL	MR_TRUE
#else
#define	MR_TABLE_DEBUG_BOOL	MR_FALSE
#endif

/*---------------------------------------------------------------------------*/

/*
** Tabling builds up two kinds of tables, both conceptually tries. For call
** tables, there is one layer in the trie for each input argument; for answer
** tables, there is one layer in the trie for each output argument. However,
** the way each trie node is implemented depends on the type of the relevant
** argument. In addition, what is stored at the tips of the call and answer
** tables also depends on what kind of tabling (e.g. loopcheck, memo, minimal
** model) is being performed on the current predicate, and (in some cases)
** on what stage the execution of the current predicate has reached.
**
** We declare trie nodes to have type MR_TrieNode, which is a pointer to
** MR_TableNode. MR_TableNode is a union of all the types that we may need
** to be able to store in trie nodes: various kinds of trie implementations,
** status indications, and answer blocks. Since in several places we write
** to the union through one member and read from it through another, it is
** important that all members be the same size; this is why the simple table
** status field is an (unsigned) integer, not an enum.
**
** The integer field is for generic code that does not know what kind of node
** the node will be; this means initialization. A value of zero means the node
** is uninitialized; this must be true for all members. (Also, see below on
** duplicate detection.)
**
** The hash table field is used when the "trie" node is implemented with a
** hash table, whether of ints, floats, strings or another type that can be
** coerced to one of these types.
**
** The fix table field implements a true trie node of fixed size, simply
** indexed by an integer.
**
** The start table field implements a dynamically expandable trie node,
** simply indexed by the difference between an integer value and a start value.
**
** The MR_loop_status member of the union gives the status of a loopcheck
** subgoal, it should be interpreted using the MR_LOOP_* macros below.
**
** The MR_memo_status member of the union gives the status of a memo subgoal,
** it should be interpreted using the MR_MEMO_* macros below. Note that this
** word, which is at the end of the chain of trie nodes given by the input
** arguments of the tabled subgoal, will be overwritten by a pointer to the
** answer block containing the output arguments when the goal succeeds;
** the MR_MEMO_SUCCEEDED status code is used only when the goal has no
** outputs, and thus no answer block. This is why code looking at
** MR_memo_status must consider "table->MR_memo_status >= MR_MEMO_BLOCK"
** to be the same as MR_MEMO_SUCCEEDED. The value MR_MEMO_FAILED is last,
** because the types memo_det_status and memo_semi_status Mercury types
** are implemented by the first three and four MR_MEMO_* macros respectively.
**
** The subgoal field contains the state of a model_non subgoal.
**
** The answer block field contains a pointer to an array of words, with
** one word per output argument.
**
** The hash table, fix table and start table members may appear at any interior
** node in the trie. The simple table status and subgoal members only appear
** at the tips of call tables. The answer block member appears only at the tips
** of call tables, either directly (for model_det and model_semi procedures),
** or indirectly inside answer lists (for model_non procedures). There are no
** answer tables for model_det and model_semi procedures, since they can only
** ever have at most one answer. You can of course have answer tables for
** model_non procedures, at whose tips you find only a duplicate indication.
** When the tip nodes of answer tables are created, they are initialized to
** zero as usual. Duplicate checking checks that the tip node is zero and
** then sets the tip to a nonzero value; this way if the answer is generated
** again, duplicate checking will fail.
**
** Note that once a tabled predicate has inserted its input arguments into
** its table and got back a pointer to the MR_TableNode representing the
** selected tip of its call table, it may in general call other tabled
** predicates and cause insertions into many tables, including its own,
** before it updates the call table tip node. This means that the tip node
** must not change address; once a tabling operation has returned an
** MR_TrieNode to its caller, that address must be valid and have the same
** meaning until the end of the computation.
**
** The implementation of start tables currently does not obey this requirement.
** This is okay, because start tables are used only by I/O tabling, which
** guarantees that there will be no insertions into the same (or any other)
** table between getting back a tip node on the one hand and updating it and
** releasing the pointer to it on the other hand.
** 
** NOTE: the mercury_type_tables module uses the expandable hash table routines
** defined in this module to implement its tables. This is the only use of the
** MR_type_table field.
*/

/* these macros are used to interpret the MR_loop_status field */
#define	MR_LOOP_INACTIVE	0
#define	MR_LOOP_ACTIVE		1

/* these macros are used to interpret the MR_memo_status field */
#define	MR_MEMO_INACTIVE	0
#define	MR_MEMO_ACTIVE		1
#define	MR_MEMO_SUCCEEDED	2
#define	MR_MEMO_FAILED		3
#define	MR_MEMO_BLOCK		4

typedef enum {
	MR_MEMO_NON_INACTIVE,
	MR_MEMO_NON_ACTIVE,
	MR_MEMO_NON_INCOMPLETE,
	MR_MEMO_NON_COMPLETE
} MR_MemoNonStatus;

typedef enum {
	MR_SUBGOAL_INACTIVE,
	MR_SUBGOAL_ACTIVE,
	MR_SUBGOAL_COMPLETE
} MR_SubgoalStatus;

struct MR_AnswerListNode_Struct {
	MR_Word			*MR_aln_answer_block;
	MR_AnswerList		MR_aln_next_answer;
};

union MR_TableNode_Union {
	MR_Integer		MR_integer;
	MR_HashTable		*MR_hash_table;
	MR_TableNode		*MR_fix_table;
	MR_TableNode		*MR_start_table;
	MR_Unsigned		MR_loop_status;
	MR_Unsigned		MR_memo_status;
	MR_Subgoal		*MR_subgoal;
	MR_MemoNonRecordPtr	MR_memo_non_record;
	MR_GeneratorPtr		MR_generator;
	MR_AnswerBlock		MR_answerblock;
	MR_Dlist		*MR_type_table;
};

#define	MR_trie_node_seen_before(t) 		((t)->MR_integer != 0)

struct MR_MemoNonRecord_Struct {
	MR_TrieNode		MR_mn_back_ptr;
	MR_MemoNonStatus	MR_mn_status;
	int			MR_mn_num_answers;
	MR_TableNode		MR_mn_answer_table;
	MR_AnswerList		MR_mn_answer_list;
	MR_AnswerList		*MR_mn_answer_list_tail;
};

/*
** The MR_ProcTableInfo structure.
**
** To enable debugging (especially performance debugging) of tabled predicates,
** the compiler generates one of these structures for each tabled predicate
** (except I/O primitives, for which it generates an MR_TableIoDecl
** structure).
**
** Each argument of a tabled predicate is an input or an output. Inputs are put
** into the call trie (stored in the tablenode field), which has one level
** per input argument. The structure of each level depends on what kind of type
** the corresponding input argument is; this is recorded in the input_steps
** field, which points to an array of size num_inputs. If the type is an enum,
** we cannot interpret the data structures on that level without also knowing
** how many alternatives the type has; this is recorded in the corresponding
** element of the enum_params array, which is likewise of size num_inputs.
** (Elements of the enum_params array that correspond to arguments whose types
** are not enums are not meaningful.)
**
** The ptis field points to an array of pseudotypeinfos of size num_inputs +
** num_outputs. The first num_inputs elements give the types of the input
** arguments, while the remaining num_outputs elements give the types of the
** output arguments. The type_params field describes where any typeinfos
** among the input arguments are at call, since without this information
** the debugger cannot turn the pseudotypeinfos pointed to by ptis field info
** typeinfos.
**
** If the collection of statistics was not enabled for this table, then the
** stats field will point to an array num_inputs MR_TableStepStats structures,
** one for each input argument. Each element of this array contains statistics
** about the corresponding level of the trie.
**
** Users can use the stats field to retrieve statistics derived from the
** entire lifetime of the table so far. To enable users to derive information
** derived only since the last such lookup, we record the information retrieved
** on each lookup in the prev_stats field (which will be NULL until the first
** such lookup).
**
** If there is no size limit on the table, then the size_limit field will be
** zero and the call_table_tips, num_call_table_tips and next_to_evict fields
** are not meaningful. If there is a size limit on the table, then the
** size_limit field says how many call table tips are allowed to exist at
** any one time, the num_call_table_tips field says how many exist at this time
** (this number will be between zero and size_limit, both inclusive),
** the call_table_tips field will point to an array of size_limit call table
** tips, of which the first num_call_table_tips will be meaningful. The
** next_to_evict field says which one of these entries is scheduled to be
** evicted next under the FIFO replacement strategy.
**
** XXX We need other fields (e.g. in hash tables and tries) to allow us
** to delete internal nodes of the trie that become empty after evictions.
*/

typedef	enum {
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_TYPE_LOOPCHECK),
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_TYPE_MEMO),
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_TYPE_MINIMAL_MODEL_STACK_COPY),
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_TYPE_MINIMAL_MODEL_OWN_STACKS)
} MR_TableType;

/*
** The definition of this type should correspond to the type table_step_kind
** in library/table_statistics.m.
*/

typedef enum {
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_DUMMY),
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_INT),
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_CHAR),
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_STRING),
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_FLOAT),
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_ENUM),
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_FOREIGN_ENUM),
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_GEN),
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_GEN_ADDR),
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_GEN_POLY),
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_GEN_POLY_ADDR),
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_TYPEINFO),
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_TYPECLASSINFO),
	MR_DEFINE_BUILTIN_ENUM_CONST(MR_TABLE_STEP_PROMISE_IMPLIED)
} MR_TableTrieStep;

typedef	MR_Unsigned	MR_Counter;

typedef enum {
	MR_TABLE_STATS_DETAIL_HASH,
	MR_TABLE_STATS_DETAIL_ENUM,
	MR_TABLE_STATS_DETAIL_START,
	MR_TABLE_STATS_DETAIL_DU,
	MR_TABLE_STATS_DETAIL_POLY,
	MR_TABLE_STATS_DETAIL_NONE
} MR_TableStepStatsKind;

struct MR_TableStepStats_Struct {
	MR_Counter			MR_tss_num_lookups;
	MR_Counter			MR_tss_num_lookups_is_dupl;
	MR_TableStepStatsKind		MR_tss_detail_kind;

	MR_Counter			MR_tss_hash_num_table_allocs;
	MR_Counter			MR_tss_hash_num_table_alloc_bytes;
	MR_Counter			MR_tss_hash_num_link_chunk_allocs;
	MR_Counter			MR_tss_hash_num_link_chunk_alloc_bytes;
	MR_Counter			MR_tss_hash_num_key_compares_not_dupl;
	MR_Counter			MR_tss_hash_num_key_compares_dupl;
	MR_Counter			MR_tss_hash_num_resizes;
	MR_Counter			MR_tss_hash_resize_old_entries;
	MR_Counter			MR_tss_hash_resize_new_entries;

	MR_Counter			MR_tss_enum_num_node_allocs;
	MR_Counter			MR_tss_enum_num_node_alloc_bytes;

	MR_Counter			MR_tss_du_num_node_allocs;
	MR_Counter			MR_tss_du_num_node_alloc_bytes;
	MR_Counter			MR_tss_du_num_arg_lookups;
	MR_Counter			MR_tss_du_num_exist_lookups;

	MR_Counter			MR_tss_start_num_allocs;
	MR_Counter			MR_tss_start_num_alloc_bytes;
};

struct MR_TableStats_Struct {
	MR_Counter			MR_ts_num_lookups;
	MR_Counter			MR_ts_num_lookups_is_dupl;
	/*
	** The number of steps is given by MR_pt_num_inputs for the call table
	** and MR_pt_num_outputs for the answer table.
	*/
	MR_TableStepStats		*MR_ts_steps;
};

#define	MR_TABLE_CALL_TABLE	0
#define	MR_TABLE_ANSWER_TABLE	1

#define	MR_TABLE_STATS_CURR	0
#define	MR_TABLE_STATS_PREV	1

struct MR_TableStepDesc_Struct {
	MR_ConstString			MR_tsd_var_name;
	MR_TableTrieStep		MR_tsd_trie_step;
	MR_Integer			MR_tsd_trie_enum_param;
};

struct MR_ProcTableInfo_Struct {
	MR_TableType			MR_pt_table_type;
	int				MR_pt_num_inputs;
	int				MR_pt_num_outputs;
	int				MR_pt_has_answer_table;
	const MR_PseudoTypeInfo		*MR_pt_ptis;
	const MR_TypeParamLocns		*MR_pt_type_params;

	MR_TableNode			MR_pt_tablenode;

	/*
	** The index should be either MR_TABLE_CALL_TABLE or
	** MR_TABLE_ANSWER_TABLE. The size of the pointed-to array is
	** MR_pt_num_inputs for MR_TABLE_CALL_TABLE and MR_pt_num_outputs
	** for MR_TABLE_ANSWER_TABLE.
	*/
	const MR_TableStepDesc		*MR_pt_steps_desc[2];

	/*
	** The first index should be either MR_TABLE_CALL_TABLE or
	** MR_TABLE_ANSWER_TABLE, while the second index should be either
	** MR_TABLE_STATS_CURR or MR_TABLE_STATS_PREV.
	*/
	MR_TableStats			MR_pt_stats[2][2];

	MR_Unsigned			MR_pt_size_limit;
	MR_TrieNode			*MR_pt_call_table_tips;
	MR_Unsigned			MR_pt_num_call_table_tips;
	MR_Unsigned			MR_pt_next_to_evict;
};

/* This type is only for backward compatibility */
typedef struct MR_Table_Gen_Struct {
	int				MR_table_gen_num_inputs;
	int				MR_table_gen_num_outputs;
	const MR_TableTrieStep		*MR_table_gen_input_steps;
	const MR_Integer		*MR_table_gen_enum_params;
	const MR_PseudoTypeInfo		*MR_table_gen_ptis;
	const MR_TypeParamLocns		*MR_table_gen_type_params;
} MR_Table_Gen;

/*---------------------------------------------------------------------------*/

/*
** The functions defined here should be used only via the macros defined
** in mercury_tabling_macros.h.
**
** These functions look to see if the given key is in the given table.
** If it is, they return the address of the data pointer associated with
** the key. If it is not, they create a new element for the key in the table
** and return the address of its data pointer.
*/

/*
** These functions assume that the table is a dynamically resizable hash table.
*/

extern	MR_TrieNode	MR_int_hash_lookup_or_add(MR_TrieNode table,
				MR_Integer key);
extern	MR_TrieNode	MR_int_hash_lookup_or_add_stats(
				MR_TableStepStats *stats, MR_TrieNode table,
				MR_Integer key);
extern	MR_TrieNode	MR_float_hash_lookup_or_add(MR_TrieNode table,
				MR_Float key);
extern	MR_TrieNode	MR_float_hash_lookup_or_add_stats(
				MR_TableStepStats *stats, MR_TrieNode table,
				MR_Float key);
extern	MR_TrieNode	MR_string_hash_lookup_or_add(MR_TrieNode table,
				MR_ConstString key);
extern	MR_TrieNode	MR_string_hash_lookup_or_add_stats(
				MR_TableStepStats *stats, MR_TrieNode table,
				MR_ConstString key);
extern	MR_TrieNode	MR_bitmap_hash_lookup_or_add(MR_TrieNode table,
				MR_ConstBitmapPtr key);
extern	MR_TrieNode	MR_bitmap_hash_lookup_or_add_stats(
				MR_TableStepStats *stats, MR_TrieNode table,
				MR_ConstBitmapPtr key);
extern	MR_TrieNode	MR_word_hash_lookup_or_add(MR_TrieNode table,
				MR_Word key);
extern	MR_TrieNode	MR_word_hash_lookup_or_add_stats(
				MR_TableStepStats *stats, MR_TrieNode table,
				MR_Word key);

/*
** These functions assume that the table is a statically sized array,
** with the index ranging from 0 to range - 1.
*/

extern	MR_TrieNode	MR_int_fix_index_enum_lookup_or_add(MR_TrieNode table,
				MR_Integer range, MR_Integer key);
extern	MR_TrieNode	MR_int_fix_index_enum_lookup_or_add_stats(
				MR_TableStepStats *stats, MR_TrieNode table,
				MR_Integer range, MR_Integer key);

extern	MR_TrieNode	MR_int_fix_index_du_lookup_or_add(MR_TrieNode table,
				MR_Integer range, MR_Integer key);
extern	MR_TrieNode	MR_int_fix_index_du_lookup_or_add_stats(
				MR_TableStepStats *stats, MR_TrieNode table,
				MR_Integer range, MR_Integer key);

/*
** These functions assume that the table is an expandable array,
** with the smallest valid index value being start.
*/

extern	MR_TrieNode	MR_int_start_index_lookup_or_add(MR_TrieNode table,
				MR_Integer start, MR_Integer key);
extern	MR_TrieNode	MR_int_start_index_lookup_or_add_stats(
				MR_TableStepStats *stats, MR_TrieNode table,
				MR_Integer start, MR_Integer key);

/*
** These functions table type_infos in a hash table.
*/

extern	MR_TrieNode	MR_type_info_lookup_or_add(MR_TrieNode table,
				MR_TypeInfo type_info);
extern	MR_TrieNode	MR_type_info_lookup_or_add_stats(
				MR_TableStepStats *stats, MR_TrieNode table,
				MR_TypeInfo type_info);

/*
** These functions table typeclass_infos in a hash table.
*/

extern	MR_TrieNode	MR_type_class_info_lookup_or_add(MR_TrieNode table,
				MR_Word *type_class_info);
extern	MR_TrieNode	MR_type_class_info_lookup_or_add_stats(
				MR_TableStepStats *stats, MR_TrieNode table,
				MR_Word *type_class_info);

/*
** These functions table values of arbitrary types; the form of the data
** structure depends on the actual type of the value. The tabling is done
** by tabling all the function symbols of the value; unlike
** MR_word_hash_lookup, this function *does* guarantee that all duplicates
** will be detected.
*/

extern	MR_TrieNode	MR_table_type(MR_TrieNode table,
				MR_TypeInfo type_info, MR_Word data_value);
extern	MR_TrieNode	MR_table_type_debug(MR_TrieNode table,
				MR_TypeInfo type_info, MR_Word data_value);
extern	MR_TrieNode	MR_table_type_stats(
				MR_TableStepStats *stats, MR_TrieNode table,
				MR_TypeInfo type_info, MR_Word data_value);
extern	MR_TrieNode	MR_table_type_stats_debug(
				MR_TableStepStats *stats, MR_TrieNode table,
				MR_TypeInfo type_info, MR_Word data_value);
extern	MR_TrieNode	MR_table_type_back(MR_TrieNode table,
				MR_TypeInfo type_info, MR_Word data_value);
extern	MR_TrieNode	MR_table_type_debug_back(MR_TrieNode table,
				MR_TypeInfo type_info, MR_Word data_value);
extern	MR_TrieNode	MR_table_type_stats_back(
				MR_TableStepStats *stats, MR_TrieNode table,
				MR_TypeInfo type_info, MR_Word data_value);
extern	MR_TrieNode	MR_table_type_stats_debug_back(
				MR_TableStepStats *stats, MR_TrieNode table,
				MR_TypeInfo type_info, MR_Word data_value);

/*
** These functions look to see if the given key is in the given table.
** If it is, they return the address of the data pointer associated with
** the key. If it is not, they return NULL.
**
** These functions assume that the table is a dynamically resizable hash table.
*/

extern	MR_TrieNode	MR_int_hash_lookup(MR_TrieNode table,
				MR_Integer key);
extern	MR_TrieNode	MR_float_hash_lookup(MR_TrieNode table,
				MR_Float key);
extern	MR_TrieNode	MR_string_hash_lookup(MR_TrieNode table,
				MR_ConstString key);
extern	MR_TrieNode	MR_bitmap_hash_lookup(MR_TrieNode table,
				MR_ConstBitmapPtr key);
extern	MR_TrieNode	MR_word_hash_lookup(MR_TrieNode table,
				MR_Word data_value);

/*
** These functions return a dynamically resizable array (using the primitives
** in mercury_array_macros.h) containing all the elements in the given
** dynamically resizable hash table.
*/

extern	MR_bool		MR_get_int_hash_table_contents(MR_TrieNode t,
				MR_Integer **values_ptr, int *value_next_ptr);
extern	MR_bool		MR_get_float_hash_table_contents(MR_TrieNode t,
				MR_Float **values_ptr, int *value_next_ptr);
extern	MR_bool		MR_get_string_hash_table_contents(MR_TrieNode t,
				MR_ConstString **values_ptr,
				int *value_next_ptr);
extern	MR_bool		MR_get_bitmap_hash_table_contents(MR_TrieNode t,
				MR_ConstBitmapPtr **values_ptr,
				int *value_next_ptr);

/*
** This function prints statistics about the operation of tabling, if the
** collection of such statistics is enabled, on the given stream.
*/

extern	void		MR_table_report_statistics(FILE *fp);

/*
** These functions return printable representations of the MR_loop_status
** MR_memo_status and MR_mn_status fields.
*/

extern	const char	*MR_loopcheck_status(MR_Unsigned);
extern	const char	*MR_memo_status(MR_Unsigned);
extern	const char	*MR_memo_non_status(MR_MemoNonStatus);

/*
** These functions print the tips of the call tables for loopcheck and memo
** tabled predicates to fp.
*/

extern	void		MR_print_loopcheck_tip(FILE *fp,
				const MR_ProcLayout *proc, MR_TrieNode table);
extern	void		MR_print_memo_tip(FILE *fp,
				const MR_ProcLayout *proc, MR_TrieNode table);
extern	void		MR_print_memo_non_record(FILE *fp,
				const MR_ProcLayout *proc,
				MR_MemoNonRecordPtr record);

/*
** Prints the given answer_block of the given procedure to fp.
*/

extern	void		MR_print_answerblock(FILE *fp,
				const MR_ProcLayout *proc,
				MR_Word *answer_block);

/*---------------------------------------------------------------------------*/

#ifndef MR_NATIVE_GC

  #define MR_TABLE_NEW(type)						\
	MR_GC_NEW_ATTRIB(type, MR_ALLOC_SITE_TABLING)

  #define MR_TABLE_NEW_ARRAY(type, count)				\
	MR_GC_NEW_ARRAY_ATTRIB(type, (count), MR_ALLOC_SITE_TABLING)

  #define MR_TABLE_RESIZE_ARRAY(ptr, type, count)			\
	MR_GC_RESIZE_ARRAY_ATTRIB((ptr), type, (count))

  #define MR_table_allocate_words(size)					\
	((MR_Word *) MR_GC_malloc_attrib(sizeof(MR_Word) * (size),      \
            MR_ALLOC_SITE_TABLING))

  #define MR_table_allocate_struct(type)				\
	((type *) MR_GC_malloc_attrib(sizeof(type),                     \
            MR_ALLOC_SITE_TABLING))

  #define MR_table_allocate_structs(num, type)				\
	((type *) MR_GC_malloc_attrib(sizeof(type) * (num),             \
            MR_ALLOC_SITE_TABLING))

  #define MR_table_free(pointer)					\
	MR_GC_free_attrib((pointer))

#else /* MR_NATIVE_GC */

  #define MR_TABLE_NATIVE_GC_MSG					\
	"Sorry, not implemented: tabling in native gc grades"

  #define MR_TABLE_NEW(type)						\
	(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG),			\
	(void *) NULL)
  #define MR_TABLE_NEW_ARRAY(type, count)				\
	(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG),			\
	(void *) NULL)
  #define MR_TABLE_RESIZE_ARRAY(pointer, type, count)			\
	(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG),			\
	(void *) NULL)
#if 0
  #define MR_table_allocate_bytes(size)					\
	(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG),			\
	(void *) NULL)
#endif
  #define MR_table_allocate_words(size)					\
	(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), 			\
	(void *) NULL)
  #define MR_table_allocate_struct(type)				\
	(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), 			\
	(void *) NULL)
  #define MR_table_allocate_structs(num, type)				\
	(MR_fatal_error(MR_TABLE_NATIVE_GC_MSG), 			\
	(void *) NULL)
  #define MR_table_free(pointer)					\
	MR_fatal_error(MR_TABLE_NATIVE_GC_MSG)

#endif /* MR_NATIVE_GC */

/*
** XXX The extra memory attribution word is not yet copied.
*/
#define MR_table_copy_words(dest, source, size)				\
	(MR_CHECK_EXPR_TYPE((dest), MR_Word *),				\
	(MR_CHECK_EXPR_TYPE((source), MR_Word *),			\
	MR_memcpy((char *) (dest), (char *) (source),			\
		sizeof(MR_Word) * (size))))

#define MR_table_copy_structs(dest, source, num, type)			\
	(MR_CHECK_EXPR_TYPE((dest), type *),				\
	(MR_CHECK_EXPR_TYPE((source), type *),				\
	MR_memcpy((char *) (dest), (char *) (source),			\
		sizeof(type) * (num))))

/*---------------------------------------------------------------------------*/

#ifdef	MR_HIGHLEVEL_CODE
    #ifdef MR_USE_GCC_NESTED_FUNCTIONS
        extern void MR_CALL
            mercury__table_builtin__table_memo_return_all_answers_multi_2_p_0(
                MR_Box record, MR_Box *answer_block_ptr,
		MR_NestedCont cont);

	extern void MR_CALL
	    mercury__table_builtin__table_memo_return_all_answers_nondet_2_p_0(
	        MR_Box record, MR_Box *answer_block_ptr,
		MR_NestedCont cont);
    #else	/* ! MR_USE_GCC_NESTED_FUNCTIONS */
        extern void MR_CALL
             mercury__table_builtin__table_memo_return_all_answers_multi_2_p_0(
                MR_Box record, MR_Box *answer_block_ptr,
                MR_Cont cont, void *cont_env_ptr);
        
	extern void MR_CALL
              mercury__table_builtin__table_memo_return_all_answers_nondet_2_p_0(
                MR_Box record, MR_Box *answer_block_ptr,
                MR_Cont cont, void *cont_env_ptr);
    #endif /* MR_USE_GCC_NESTED_FUNCTIONS */

#else	/* ! MR_HIGHLEVEL_CODE */
  #define MR_MEMO_NON_RET_ALL_NONDET_ENTRY				\
	MR_proc_entry_user_name(table_builtin,				\
		table_memo_return_all_answers_nondet, 2, 0)
  #define MR_MEMO_NON_RET_ALL_MULTI_ENTRY				\
	MR_proc_entry_user_name(table_builtin,				\
		table_memo_return_all_answers_multi, 2, 0)

  MR_declare_entry(MR_MEMO_NON_RET_ALL_NONDET_ENTRY);
  MR_declare_entry(MR_MEMO_NON_RET_ALL_MULTI_ENTRY);
#endif	/* MR_HIGHLEVEL_CODE */

/*---------------------------------------------------------------------------*/

#include "mercury_tabling_macros.h"
#include "mercury_tabling_preds.h"

#include "mercury_stack_layout.h"	/* for MR_ProcLayout and */
					/* MR_TypeParamLocns */

#endif	/* not MERCURY_TABLING_H */
