aboutsummaryrefslogtreecommitdiff
path: root/ic-reals-6.3/base/strictAlt.c
blob: 9ae4434996ec27384b253fff16e0c49de9b21c93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * Copyright (C) 2000, Imperial College
 *
 * This file is part of the Imperial College Exact Real Arithmetic Library.
 * See the copyright notice included in the distribution for conditions
 * of use.
 */

#include <stdio.h>
#include "real.h"
#include "real-impl.h"

/*
 * The conditional is implemented as a function:
 *
 *  void * realAlt(Bool, *void, ...)
 * 
 * where the arguments are a list of guard/value pairs. This is implemented
 * using stdarg(3). The last guard must be the constant DEFAULT_GUARD.
 */

typedef struct ALT_CELL {
	Bool guard;
	void *value;
	struct ALT_CELL *next;
} AltCell;

#include <stdarg.h>

/*
 * ### A better scheme would be to put the alt in the heap as well. Perhaps
 * later.
 */
void *
realAlt(Bool guard, void *value, ...)
{
	va_list ap;
	AltCell *head, *ptr;
	AltCell **prev;
	void *defaultValue;
	void runStack();

	/*
	 * The caller is a wally if the first argument is the default guard.
	 * But we accept it.
	 */
	if ((unsigned) guard == DEFAULT_GUARD)
		return value;

	if (guard->gen.tag.value == LAZY_TRUE)
		return value;

	if ((head = (AltCell *) alloca(sizeof(AltCell))) == NULL)
		Error(FATAL, E_INT, "realAlt", "alloca failed");

	head->guard = guard;
	head->value = value;
	head->next = NULL;
	ptr = head;

	/*
	 * Now we consume the arguments. Each is a guard/value pair. If
	 * the guard is true, then we just return the value. If not then
	 * we allocate a cell with the guard and value and add it to
	 * the list of cells.
	 */
	va_start(ap, value);
	while ((unsigned) (guard = va_arg(ap, Bool)) != DEFAULT_GUARD) {
		value = va_arg(ap, void *);

		if (guard->gen.tag.value == LAZY_TRUE)
			return value;

		if ((ptr->next = (AltCell *) alloca(sizeof(AltCell))) == NULL)
			Error(FATAL, E_INT, "realAlt", "alloca failed");

		ptr = ptr->next;
		ptr->guard = guard;
		ptr->value = value;
		ptr->next = NULL;
	}
	defaultValue = va_arg(ap, void *);
	va_end(ap);

	/*
	 * If we reach here, then we have a list of AltCells which
	 * have guards having value LAZY_UNKNOWN. We now walk down this
	 * list repeatedly. For each alternative, we force the next value
	 * in the boolean stream. If any guard becomes true, then we
	 * return the corresponding value. If something becomes false,
	 * it gets removed from the list. The loop ends when the list
	 * becomes empty whereupon we return the default value provided
	 * at the end of the argument list.
	 */
	ptr = head;
	prev = &head;
	while (ptr != NULL) {
		if (ptr->guard->gen.tag.value == LAZY_UNKNOWN) {
			PUSH_2(ptr->guard->gen.force, ptr->guard);
			runStack();
		}
		switch (ptr->guard->gen.tag.value) {
			case LAZY_TRUE :
				return ptr->value;
				break;
			case LAZY_FALSE :
				*prev = ptr->next; /* unlink the cell */
				ptr = ptr->next;
				break;
			case LAZY_UNKNOWN :
				prev = &(ptr->next);
				ptr = ptr->next;
				break;
			default :
				Error(FATAL, E_INT, "realAlt",
								"invalid boolean value encountered");
				break;
		}

		/*
		 * Reached the end of the list so start from the beginning again.
		 */
		if (ptr == NULL) {
			ptr = head;
			prev = &head;
		}
	}
	return defaultValue;
}