File: memoize.c

package info (click to toggle)
saml 970418-9
  • links: PTS
  • area: main
  • in suites: woody
  • size: 1,188 kB
  • ctags: 1,703
  • sloc: ansic: 17,186; sh: 2,573; yacc: 497; perl: 264; makefile: 242; python: 242
file content (207 lines) | stat: -rw-r--r-- 4,646 bytes parent folder | download | duplicates (3)
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/*
 * Copyright 1995,96 Thierry Bousch
 * Licensed under the Gnu Public License, Version 2
 *
 * $Id: memoize.c,v 2.6 1996/09/18 10:02:56 bousch Exp $
 *
 * Memoization of worthwhile objects. This requires the gdbm(3) library.
 */

#include <assert.h>
#include <errno.h>
#include <gdbm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "saml.h"
#include "saml-parse.h"
#include "induce.h"

typedef struct _memo_entry {
	struct _memo_entry *next;
	int arity;
	const char* rootname;
	int slot;
} PRECIOUS_ENTRY;

typedef struct {
	const char *filename;
	GDBM_FILE handle;
} DB_ENTRY;

#define MAX_DB_ENTRIES	30
static DB_ENTRY db_entries[MAX_DB_ENTRIES];
static int nb_db_entries = 0, current_db_entry = -1;

static char temporary_memo[] = _PATH_TMPMEMO;
static PRECIOUS_ENTRY *precious_list[256];

int register_memo (const char *filename)
{
	GDBM_FILE gf;
	int i;

	filename = tilde_expand(filename);
	/* Already registered ? */
	for (i = 0; i < nb_db_entries; i++)
		if (strcmp(db_entries[i].filename,filename) == 0)
			return (current_db_entry = i);

	if (nb_db_entries >= MAX_DB_ENTRIES-1) {
		fprintf(stderr,
		    "induce: too many memos (max %d), skipping `%s'\n",
		    MAX_DB_ENTRIES, filename);
		return (current_db_entry = -1);
	}
	if (strcmp(filename,"-") == 0) {
		mktemp(temporary_memo);
		gf = gdbm_open(temporary_memo, 0, GDBM_WRCREAT|GDBM_FAST,
			0666, NULL);
		if (gf == NULL)
			perror("induce: gdbm_open");
		unlink(temporary_memo);
	} else {
		/* The prototype of gdbm_open() ought to be fixed, really */
		gf = gdbm_open(filename, 0, GDBM_WRCREAT, 0666, NULL);
		if (gf == NULL)
			perror("induce: gdbm_open");
	}
	current_db_entry = -1;
	if (gf) {
		current_db_entry = nb_db_entries++;
		db_entries[current_db_entry].filename = filename;
		db_entries[current_db_entry].handle = gf;
	}
	return current_db_entry;
}
	
static inline int hash (const char *rootname, int arity)
{
	/*
	 * Takes two bits from the arity, six from rootname[0], and
	 * thus returns a number in [0..255].
	 */
	return (*rootname & 63) | ((arity & 3) << 6);
}

static int get_memo2 (const char* rootname, int arity)
{
	PRECIOUS_ENTRY *p;
	int h = hash(rootname, arity);

	for (p = precious_list[h]; p; p = p->next)
		if (p->arity == arity && !strcmp(p->rootname,rootname))
			return p->slot;
	return -1;
}
	
static GDBM_FILE get_memo (const char *name)
{
	char *rootname, c, *p;
	int arity, slot;

	rootname = alloca(strlen(name) + 1);
	strcpy(rootname, name);
	arity = 0;
	p = strchr(rootname, '[');
	if (p != NULL) {
		arity = 1;
		*p++ = '\0';	/* Isolate the rootname */
		while ((c = *p++) != '\0')
			if (c == ',')
				++arity;
	}
	slot = get_memo2(rootname, arity);
	if (slot < 0)
		return NULL;
	return db_entries[slot].handle;
}

void declare_precious (const char *rootname, int arity)
{
	int h;
	PRECIOUS_ENTRY *p;

	if (floating_precision || current_db_entry < 0) {
		/* Memoizing is disabled. */
		return;
	}
	if (get_memo2(rootname, arity) >= 0) {
		/* Already declared as precious */
		return;
	}
	h = hash(rootname, arity);
	p = malloc(sizeof(PRECIOUS_ENTRY)); assert(p);
	p->next = precious_list[h];
	precious_list[h] = p;
	p->arity = arity;
	p->rootname = rootname;
	p->slot = current_db_entry;
}

int is_saved (const char* name)
{
	datum key;
	GDBM_FILE memo = get_memo(name);

	if (!memo)
		return 0;
	key.dptr = (char *) name;
	key.dsize = strlen(key.dptr);
	return gdbm_exists(memo, key);
}

int save_precious (vertex *v)
{
	datum key, content;
	GDBM_FILE memo = get_memo(v->name);
	int ret;

	if (!memo)
		return -1;  /* not precious */
	key.dptr = v->name;
	key.dsize = strlen(key.dptr);
	content.dptr = mref_string(v->mr);
	content.dsize = strlen(content.dptr);
	ret = gdbm_store(memo, key, content, GDBM_REPLACE);
	if (ret != 0)
		fprintf(stderr, "save_precious: store failed\n");
	return ret;
}

int retrieve_precious (vertex *v)
{
	datum key, content;
	GDBM_FILE memo = get_memo(v->name);
	mref_t model;
	int ret;

	if (!memo)
		return -1;  /* not precious */
	key.dptr = v->name;
	key.dsize = strlen(key.dptr);
	content = gdbm_fetch(memo, key);
	if (content.dptr == NULL) {
		/* Record not found */
		return -1;
	}
#if 0
	ret = parse_poly(v->mr, ST_RATIONAL, content.dptr, content.dsize);
#else
	model = mref_new();
	mref_build(model, ST_RATIONAL, "0");
	mref_cast(model, parsed_poly_type);
	saml_init_lexer_mem(content.dptr, content.dsize);
	ret = saml_parse(v->mr, model);
	mref_free(model);
#endif
	/* Gdbm does not free this space itself */
	free(content.dptr);
	if (ret != 0) {
		fprintf(stderr, "retrieve_precious(%s): syntax error\n",
			v->name);
		return -1;
	}
	return 0;
}