Files
mercury/runtime/mercury_array_macros.h
Zoltan Somogyi eeaa5eca56 Make a step towards supporting the automatic running of compiler-provided
Estimated hours taken: 4
Branches: main

Make a step towards supporting the automatic running of compiler-provided
initialization functions at startup. The idea is that in each module that
defines a solver type which wants to keep the solver state in a global
variable, the compiler will generate a function to initialize this global
variable and put a line containing

	REQUIRED_INIT function_name

in the generated .c file. Mkinit will then see this and put a call to the named
function in the program's init_modules_required function, which (once this diff
is installed) will be called from the tail end of mercury_init.

util/mkinit.c:
	Until now, mkinit didn't open .c files unless given the -x option,
	because doing so was expensive: the list of .c (and .init) files was
	scanned five times, and opening and reading each file five times is
	excessive. This diff changes that. Each file is now opened and read
	(until a line containing only ENDINIT) just once, and the info found
	therein put into some new mkinit data structures. The five scans
	through the file list now scan through these data structures instead.
	This is now fast enough to leave -x on all the time: mkinit -x now
	takes 3-4 seconds in the compiler directory, and at most 0.15s
	in the other directories.

	Add a sixth scan through the data structures to generate calls to
	the functions named in REQUIRED_INIT lines; make bunches of these calls
	the body of the program's init_modules_required function.

runtime/mercury_array_macro.h:
	Fix indentation.

runtime/mercury_dlist.[ch]:
	Move the documentation of the exported functions from the .c file
	to the .h file.

runtime/mercury_std.h:
	Add a missing () around a macro argument.
2005-08-11 01:12:53 +00:00

233 lines
12 KiB
C

/*
** vim: ts=4 sw=4 expandtab
*/
/*
** Copyright (C) 1998-2000,2002, 2004-2005 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_array_macros.h defines macros for dealing with expandable arrays.
*/
#ifndef MERCURY_ARRAY_MACROS_H
#define MERCURY_ARRAY_MACROS_H
#include "mercury_reg_workarounds.h" /* for MR_assign_structure */
/*
** The MR_ensure_room_for_next macro works with a group of three variables
** that follow the pattern
**
** Item *widgets = NULL;
** int widget_max = 0;
** int widget_next = 0;
**
** where widgets is a pointer to a MR_malloc'd array of items, widget_max
** gives the number of elements in the array, and widget_next is the
** index of the first free slot in the widgets array. Widget_max is
** zero if and only if widgets is NULL.
**
** MR_ensure_room_for_next(widget, Item, INIT_SIZE) checks whether
** there is enough room in the widgets array to add a new item.
** If not, doubles the size of the existing widgets array, or
** allocates an array of INIT_SIZE items if the widgets array
** has not been initialized before.
**
** BEWARE: YOU NEED TO BE VERY CAREFUL OF POINTERS TO OBJECTS ON THE GC HEAP:
**
** - For MR_ensure_room_for_next(), the memory is allocated with MR_malloc(),
** which means that if conservative GC is enabled, the array elements
** _MUST NOT_ point to the GC heap (or at least must not be the _only_
** pointer to any object on the GC heap); but the array address can be
** stored anywhere.
**
** - For MR_GC_ensure_room_for_next(), the memory is allocated on the GC heap,
** which means that the array elements can point to anything;
** but the array address _MUST NOT_ be stored in memory allocated with
** malloc() or MR_malloc() (unless it is also stored in some place
** which _is_ scanned by the collector).
**
** It is the caller's responsibility to deallocate the memory for the array
** if/when it is no longer needed, using MR_free() or MR_GC_free()
** respectively.
*/
#define MR_ensure_room_for_next(base, type, init) \
do { \
if (base##_next >= base##_max) { \
if (base##_max == 0) { \
base##_max = (init); \
base##s = MR_NEW_ARRAY(type, base##_max); \
} else { \
base##_max *= 2; \
base##s = MR_RESIZE_ARRAY(base##s, type, base##_max); \
} \
} \
} while(0)
#define MR_GC_ensure_room_for_next(base, type, init) \
do { \
if (base##_next >= base##_max) { \
if (base##_max == 0) { \
base##_max = (init); \
base##s = MR_GC_NEW_ARRAY(type, base##_max); \
} else { \
base##_max *= 2; \
base##s = MR_GC_RESIZE_ARRAY(base##s, type, base##_max);\
} \
} \
} while(0)
/*
** MR_ensure_big_enough makes the same assumptions as MR_ensure_room_for_next,
** and operates almost the same way. The exception is that it does not assume
** that the array grows one item at a time; instead it ensures that the array
** is big enough to contain the element at index `slot'. Since with this regime
** there is no notion of the "next" slot, this macro does not access, nor does
** it require the existence of, base##_next.
**
** BEWARE: YOU NEED TO BE VERY CAREFUL OF POINTERS TO OBJECTS ON THE GC HEAP.
** See the comment for MR_ensure_room_for_next().
*/
#define MR_ensure_big_enough(slot, base, type, init) \
do { \
if ((slot) >= base##_max) { \
if (base##_max == 0) { \
base##_max = MR_max((init), (slot) + 1); \
base##s = MR_NEW_ARRAY(type, base##_max); \
} else { \
base##_max = MR_max(base##_max * 2, (slot) + 1); \
base##s = MR_RESIZE_ARRAY(base##s, type, base##_max); \
} \
} \
} while(0)
/*
** MR_ensure_big_enough2 works like MR_ensure_big_enough, except that
** it resizes two arrays at once. These two arrays are named base##s1 and
** base##s2, and since they are always the same size, they share the
** base##_max variable.
**
** BEWARE: YOU NEED TO BE VERY CAREFUL OF POINTERS TO OBJECTS ON THE GC HEAP.
** See the comment for MR_ensure_room_for_next().
*/
#define MR_ensure_big_enough2(slot, base, s1, s2, type, init) \
do { \
if ((slot) >= base##_max) { \
if (base##_max == 0) { \
base##_max = MR_max((init), (slot) + 1); \
base##s1 = MR_NEW_ARRAY(type, base##_max); \
base##s2 = MR_NEW_ARRAY(type, base##_max); \
} else { \
base##_max = MR_max(base##_max * 2, (slot) + 1); \
base##s1 = MR_RESIZE_ARRAY(base##s1, type, base##_max); \
base##s2 = MR_RESIZE_ARRAY(base##s2, type, base##_max); \
} \
} \
} while(0)
/*
** MR_bsearch(int num_elements, int& element, MR_bool& found, COMPARE)
**
** Given a sorted array, this macro performs a binary search.
** If the search is successful, MR_bsearch sets the `found' parameter
** to MR_TRUE and the `element' parameter to the index of the desired item.
** If the search is unsuccessful, MR_bsearch sets `found' to MR_FALSE;
** `element' will be clobbered.
**
** The number of the elements in the array is given by the `num_elements'
** parameter.
** The `COMPARE' parameter should be an expression of type int which compares
** the value at the index specified by the current value of `element'
** with the desired value, and returns <0, 0, or >0 according to whether
** it is less than, equal to, or greater than the desired value.
**
** The name of the array to be searched is not explicitly a parameter;
** its identity is encoded in the boolean expression of the `COMPARE'
** parameter.
*/
#define MR_bsearch(num_elements, element, found, COMPARE) \
do { \
int lo; \
int hi; \
int diff; \
\
/* \
** We initialize `element' here only to avoid gcc \
** warnings about possibly accessing an uninitialized \
** variable in code using MR_bsearch(). \
*/ \
(element) = 0; \
lo = 0; \
hi = (num_elements) - 1; \
(found) = MR_FALSE; \
while (lo <= hi) { \
(element) = (lo + hi) / 2; \
diff = (COMPARE); \
if (diff == 0) { \
(found) = MR_TRUE; \
break; \
} else if (diff < 0) { \
lo = (element) + 1; \
} else { \
hi = (element) - 1; \
} \
} \
} while(0)
/*
** MR_find_first_match(int num_elements, int& element, MR_bool& found, COMPARE)
**
** Given a sorted array, this macro finds the first element in the array
** for which `COMPARE' is zero (MR_bsearch finds an arbitrary element).
** Otherwise, the parameters and behaviour are the same as for MR_bsearch.
*/
#define MR_find_first_match(num_elements, element, found, COMPARE) \
do { \
MR_bsearch((num_elements), (element), (found), (COMPARE)); \
if (found) { \
while ((element) > 0) { \
(element)--; \
if ((COMPARE) != 0) { \
(element)++; \
break; \
} \
} \
} \
} while (0)
/*
** MR_prepare_insert_into_sorted(array[], int& next, int& element, COMPARE)
**
** Given a sorted array of `items', this prepares for the insertion of a
** new item into the array at the proper point. It finds the index at which
** the new item should be inserted, and moves all items at and above that
** index one position to the right to make room for the new item.
**
** The `next' parameter holds the number of elements in the array;
** it is incremented by this macro. The macro returns the index of the slot
** at which the new item should be inserted in the `element' parameter.
** The `COMPARE' parameter should be an expression of type int which compares
** the item at the index specified by the current value of `element' with
** the item being inserted, and returns <0, 0, or >0 according to whether
** it is less than, equal to, or greater than the item being inserted.
*/
#define MR_prepare_insert_into_sorted(items, next, element, COMPARE) \
do { \
(element) = (next) - 1; \
while ((element) >= 0 && (COMPARE) > 0) { \
MR_assign_structure(items[element + 1], items[element]); \
(element) -= 1; \
} \
(element) += 1; \
(next) += 1; \
} while(0)
#endif /* MERCURY_ARRAY_MACROS_H */