Use string and symbol accessors in struct, throw, and array funcs
[bpt/guile.git] / libguile / struct.c
CommitLineData
651f2cd2 1/* Copyright (C) 1996,1997,1998,1999,2000,2001, 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
0f2d19dd 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
0f2d19dd 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
73be1d9e 17 */
1bbd0b84 18
0f2d19dd 19\f
dbb605f5 20#ifdef HAVE_CONFIG_H
a6f7f57d
RB
21# include <config.h>
22#endif
0f2d19dd 23
a0599745 24#include "libguile/_scm.h"
4e047c3e 25#include "libguile/async.h"
a0599745
MD
26#include "libguile/chars.h"
27#include "libguile/eval.h"
28#include "libguile/alist.h"
29#include "libguile/weaks.h"
30#include "libguile/hashtab.h"
31#include "libguile/ports.h"
32#include "libguile/strings.h"
27646f41 33#include "libguile/srfi-13.h"
a0599745
MD
34
35#include "libguile/validate.h"
36#include "libguile/struct.h"
0f2d19dd 37
d15ad007
LC
38#include "libguile/eq.h"
39
95b88819
GH
40#ifdef HAVE_STRING_H
41#include <string.h>
42#endif
43
0f2d19dd
JB
44\f
45
46static SCM required_vtable_fields = SCM_BOOL_F;
98d5f601 47SCM scm_struct_table;
0f2d19dd
JB
48
49\f
a1ec6916 50SCM_DEFINE (scm_make_struct_layout, "make-struct-layout", 1, 0, 0,
1bbd0b84 51 (SCM fields),
b380b885 52 "Return a new structure layout object.\n\n"
7c31152f 53 "@var{fields} must be a string made up of pairs of characters\n"
b380b885
MD
54 "strung together. The first character of each pair describes a field\n"
55 "type, the second a field protection. Allowed types are 'p' for\n"
56 "GC-protected Scheme data, 'u' for unprotected binary data, and 's' for\n"
04323af4 57 "a field that points to the structure itself. Allowed protections\n"
9401323e 58 "are 'w' for mutable fields, 'r' for read-only fields, and 'o' for opaque\n"
b380b885
MD
59 "fields. The last field protection specification may be capitalized to\n"
60 "indicate that the field is a tail-array.")
1bbd0b84 61#define FUNC_NAME s_scm_make_struct_layout
0f2d19dd
JB
62{
63 SCM new_sym;
d1ca2c64 64 SCM_VALIDATE_STRING (1, fields);
27646f41 65 scm_t_wchar c;
2ade72d7 66
1bbd0b84 67 { /* scope */
1be6b49c 68 size_t len;
0f2d19dd
JB
69 int x;
70
cc95e00a 71 len = scm_i_string_length (fields);
2ade72d7
DH
72 if (len % 2 == 1)
73 SCM_MISC_ERROR ("odd length field specification: ~S",
1afff620 74 scm_list_1 (fields));
2ade72d7 75
0f2d19dd
JB
76 for (x = 0; x < len; x += 2)
77 {
27646f41 78 switch (c = scm_i_string_ref (fields, x))
0f2d19dd
JB
79 {
80 case 'u':
81 case 'p':
82#if 0
83 case 'i':
84 case 'd':
85#endif
86 case 's':
87 break;
88 default:
2ade72d7 89 SCM_MISC_ERROR ("unrecognized field type: ~S",
27646f41 90 scm_list_1 (SCM_MAKE_CHAR (c)));
0f2d19dd
JB
91 }
92
27646f41 93 switch (c = scm_i_string_ref (fields, x + 1))
0f2d19dd
JB
94 {
95 case 'w':
27646f41 96 if (scm_i_string_ref (fields, x) == 's')
2ade72d7 97 SCM_MISC_ERROR ("self fields not writable", SCM_EOL);
0f2d19dd
JB
98 case 'r':
99 case 'o':
100 break;
2c36c351
MD
101 case 'R':
102 case 'W':
103 case 'O':
27646f41 104 if (scm_i_string_ref (fields, x) == 's')
2ade72d7
DH
105 SCM_MISC_ERROR ("self fields not allowed in tail array",
106 SCM_EOL);
107 if (x != len - 2)
108 SCM_MISC_ERROR ("tail array field must be last field in layout",
109 SCM_EOL);
2c36c351 110 break;
0f2d19dd 111 default:
2ade72d7 112 SCM_MISC_ERROR ("unrecognized ref specification: ~S",
27646f41 113 scm_list_1 (SCM_MAKE_CHAR (c)));
0f2d19dd
JB
114 }
115#if 0
27646f41 116 if (scm_i_string_ref (fields, x, 'd'))
0f2d19dd 117 {
27646f41 118 if (!scm_i_string_ref (fields, x+2, '-'))
2ade72d7 119 SCM_MISC_ERROR ("missing dash field at position ~A",
e11e83f3 120 scm_list_1 (scm_from_int (x / 2)));
0f2d19dd
JB
121 x += 2;
122 goto recheck_ref;
123 }
124#endif
125 }
cc95e00a 126 new_sym = scm_string_to_symbol (fields);
0f2d19dd 127 }
8824ac88
MV
128 scm_remember_upto_here_1 (fields);
129 return new_sym;
0f2d19dd 130}
1bbd0b84 131#undef FUNC_NAME
0f2d19dd
JB
132
133\f
134
135
1cc91f1b 136
f7620510 137static void
92c2555f 138scm_struct_init (SCM handle, SCM layout, scm_t_bits * mem, int tail_elts, SCM inits)
0f2d19dd 139{
27646f41 140 scm_t_wchar prot = 0;
cc95e00a 141 int n_fields = scm_i_symbol_length (layout) / 2;
2c36c351 142 int tailp = 0;
27646f41 143 int i;
d8c40b9f 144
27646f41 145 i = -2;
0f2d19dd
JB
146 while (n_fields)
147 {
2c36c351
MD
148 if (!tailp)
149 {
27646f41
MG
150 i += 2;
151 prot = scm_i_symbol_ref (layout, i+1);
2c36c351
MD
152 if (SCM_LAYOUT_TAILP (prot))
153 {
154 tailp = 1;
155 prot = prot == 'R' ? 'r' : prot == 'W' ? 'w' : 'o';
d8c40b9f 156 *mem++ = tail_elts;
2c36c351
MD
157 n_fields += tail_elts - 1;
158 if (n_fields == 0)
159 break;
160 }
161 }
27646f41 162 switch (scm_i_symbol_ref (layout, i))
0f2d19dd
JB
163 {
164#if 0
165 case 'i':
2c36c351 166 if ((prot != 'r' && prot != 'w') || inits == SCM_EOL)
0f2d19dd
JB
167 *mem = 0;
168 else
169 {
b9bd8526 170 *mem = scm_to_long (SCM_CAR (inits));
0f2d19dd
JB
171 inits = SCM_CDR (inits);
172 }
173 break;
174#endif
175
176 case 'u':
d2e53ed6 177 if ((prot != 'r' && prot != 'w') || scm_is_null (inits))
0f2d19dd
JB
178 *mem = 0;
179 else
180 {
b9bd8526 181 *mem = scm_to_ulong (SCM_CAR (inits));
0f2d19dd
JB
182 inits = SCM_CDR (inits);
183 }
184 break;
185
186 case 'p':
d2e53ed6 187 if ((prot != 'r' && prot != 'w') || scm_is_null (inits))
d8c40b9f 188 *mem = SCM_UNPACK (SCM_BOOL_F);
0f2d19dd
JB
189 else
190 {
d8c40b9f 191 *mem = SCM_UNPACK (SCM_CAR (inits));
0f2d19dd
JB
192 inits = SCM_CDR (inits);
193 }
194
195 break;
196
197#if 0
198 case 'd':
2c36c351 199 if ((prot != 'r' && prot != 'w') || inits == SCM_EOL)
0f2d19dd
JB
200 *((double *)mem) = 0.0;
201 else
202 {
a5bfe84d 203 *mem = scm_num2dbl (SCM_CAR (inits), "scm_struct_init");
0f2d19dd
JB
204 inits = SCM_CDR (inits);
205 }
206 fields_desc += 2;
207 break;
208#endif
209
210 case 's':
d8c40b9f 211 *mem = SCM_UNPACK (handle);
0f2d19dd
JB
212 break;
213 }
214
0f2d19dd
JB
215 n_fields--;
216 mem++;
217 }
218}
219
220
a1ec6916 221SCM_DEFINE (scm_struct_p, "struct?", 1, 0, 0,
1bbd0b84 222 (SCM x),
0233bfc1 223 "Return @code{#t} iff @var{x} is a structure object, else\n"
942e5b91 224 "@code{#f}.")
1bbd0b84 225#define FUNC_NAME s_scm_struct_p
0f2d19dd 226{
7888309b 227 return scm_from_bool(SCM_STRUCTP (x));
0f2d19dd 228}
1bbd0b84 229#undef FUNC_NAME
0f2d19dd 230
a1ec6916 231SCM_DEFINE (scm_struct_vtable_p, "struct-vtable?", 1, 0, 0,
1bbd0b84 232 (SCM x),
0233bfc1 233 "Return @code{#t} iff @var{x} is a vtable structure.")
1bbd0b84 234#define FUNC_NAME s_scm_struct_vtable_p
0f2d19dd
JB
235{
236 SCM layout;
92c2555f 237 scm_t_bits * mem;
27646f41
MG
238 SCM tmp;
239 size_t len;
0f2d19dd
JB
240
241 if (!SCM_STRUCTP (x))
242 return SCM_BOOL_F;
243
244 layout = SCM_STRUCT_LAYOUT (x);
245
cc95e00a
MV
246 if (scm_i_symbol_length (layout)
247 < scm_i_string_length (required_vtable_fields))
0f2d19dd
JB
248 return SCM_BOOL_F;
249
27646f41
MG
250 len = scm_i_string_length (required_vtable_fields);
251 tmp = scm_string_eq (scm_symbol_to_string (layout),
252 required_vtable_fields,
253 scm_from_size_t (0),
254 scm_from_size_t (len),
255 scm_from_size_t (0),
256 scm_from_size_t (len));
257 if (scm_is_false (tmp))
0f2d19dd
JB
258 return SCM_BOOL_F;
259
260 mem = SCM_STRUCT_DATA (x);
261
cc95e00a 262 return scm_from_bool (scm_is_symbol (SCM_PACK (mem[scm_vtable_index_layout])));
0f2d19dd 263}
1bbd0b84 264#undef FUNC_NAME
0f2d19dd 265
14d1400f
JB
266
267/* All struct data must be allocated at an address whose bottom three
268 bits are zero. This is because the tag for a struct lives in the
269 bottom three bits of the struct's car, and the upper bits point to
270 the data of its vtable, which is a struct itself. Thus, if the
271 address of that data doesn't end in three zeros, tagging it will
272 destroy the pointer.
273
274 This function allocates a block of memory, and returns a pointer at
275 least scm_struct_n_extra_words words into the block. Furthermore,
276 it guarantees that that pointer's least three significant bits are
277 all zero.
278
279 The argument n_words should be the number of words that should
280 appear after the returned address. (That is, it shouldn't include
281 scm_struct_n_extra_words.)
282
283 This function initializes the following fields of the struct:
284
ad196599 285 scm_struct_i_ptr --- the actual start of the block of memory; the
14d1400f
JB
286 address you should pass to 'free' to dispose of the block.
287 This field allows us to both guarantee that the returned
288 address is divisible by eight, and allow the GC to free the
289 block.
290
291 scm_struct_i_n_words --- the number of words allocated to the
292 block, including the extra fields. This is used by the GC.
293
14d1400f
JB
294 Ugh. */
295
296
92c2555f 297scm_t_bits *
4c9419ac 298scm_alloc_struct (int n_words, int n_extra, const char *what)
14d1400f 299{
92c2555f 300 int size = sizeof (scm_t_bits) * (n_words + n_extra) + 7;
4c9419ac 301 void * block = scm_gc_malloc (size, what);
14d1400f
JB
302
303 /* Adjust the pointer to hide the extra words. */
92c2555f 304 scm_t_bits * p = (scm_t_bits *) block + n_extra;
14d1400f
JB
305
306 /* Adjust it even further so it's aligned on an eight-byte boundary. */
92c2555f 307 p = (scm_t_bits *) (((scm_t_bits) p + 7) & ~7);
14d1400f 308
ad196599 309 /* Initialize a few fields as described above. */
92c2555f
MV
310 p[scm_struct_i_free] = (scm_t_bits) scm_struct_free_standard;
311 p[scm_struct_i_ptr] = (scm_t_bits) block;
c8045e8d 312 p[scm_struct_i_n_words] = n_words;
ad196599 313 p[scm_struct_i_flags] = 0;
14d1400f
JB
314
315 return p;
316}
317
4c9419ac 318void
92c2555f
MV
319scm_struct_free_0 (scm_t_bits * vtable SCM_UNUSED,
320 scm_t_bits * data SCM_UNUSED)
ad196599 321{
ad196599
MD
322}
323
4c9419ac 324void
92c2555f 325scm_struct_free_light (scm_t_bits * vtable, scm_t_bits * data)
ad196599 326{
4c9419ac
MV
327 size_t n = vtable [scm_struct_i_size] & ~SCM_STRUCTF_MASK;
328 scm_gc_free (data, n, "struct");
ad196599
MD
329}
330
4c9419ac 331void
92c2555f 332scm_struct_free_standard (scm_t_bits * vtable SCM_UNUSED, scm_t_bits * data)
ad196599 333{
c8045e8d 334 size_t n = (data[scm_struct_i_n_words] + scm_struct_n_extra_words)
92c2555f 335 * sizeof (scm_t_bits) + 7;
4c9419ac 336 scm_gc_free ((void *) data[scm_struct_i_ptr], n, "heavy struct");
ad196599
MD
337}
338
4c9419ac 339void
92c2555f 340scm_struct_free_entity (scm_t_bits * vtable SCM_UNUSED, scm_t_bits * data)
ad196599 341{
c8045e8d 342 size_t n = (data[scm_struct_i_n_words] + scm_struct_entity_n_extra_words)
92c2555f 343 * sizeof (scm_t_bits) + 7;
4c9419ac 344 scm_gc_free ((void *) data[scm_struct_i_ptr], n, "entity struct");
ad196599 345}
14d1400f 346
b4a1358c
MD
347static void *
348scm_struct_gc_init (void *dummy1 SCM_UNUSED,
349 void *dummy2 SCM_UNUSED,
350 void *dummy3 SCM_UNUSED)
351{
352 scm_i_structs_to_free = SCM_EOL;
353 return 0;
354}
355
08c880a3 356static void *
e81d98ec
DH
357scm_free_structs (void *dummy1 SCM_UNUSED,
358 void *dummy2 SCM_UNUSED,
359 void *dummy3 SCM_UNUSED)
08c880a3 360{
ffd72400 361 SCM newchain = scm_i_structs_to_free;
08c880a3
MD
362 do
363 {
364 /* Mark vtables in GC chain. GC mark set means delay freeing. */
365 SCM chain = newchain;
d2e53ed6 366 while (!scm_is_null (chain))
08c880a3
MD
367 {
368 SCM vtable = SCM_STRUCT_VTABLE (chain);
369 if (SCM_STRUCT_GC_CHAIN (vtable) != 0 && vtable != chain)
569aa529 370 SCM_SET_STRUCT_MARK (vtable);
08c880a3
MD
371 chain = SCM_STRUCT_GC_CHAIN (chain);
372 }
373 /* Free unmarked structs. */
374 chain = newchain;
375 newchain = SCM_EOL;
d2e53ed6 376 while (!scm_is_null (chain))
08c880a3
MD
377 {
378 SCM obj = chain;
379 chain = SCM_STRUCT_GC_CHAIN (chain);
569aa529 380 if (SCM_STRUCT_MARK_P (obj))
08c880a3 381 {
569aa529 382 SCM_CLEAR_STRUCT_MARK (obj);
08c880a3
MD
383 SCM_SET_STRUCT_GC_CHAIN (obj, newchain);
384 newchain = obj;
385 }
386 else
387 {
d15ad007 388 scm_t_bits * vtable_data = SCM_STRUCT_VTABLE_DATA (obj);
92c2555f
MV
389 scm_t_bits * data = SCM_STRUCT_DATA (obj);
390 scm_t_struct_free free_struct_data
391 = ((scm_t_struct_free) vtable_data[scm_struct_i_free]);
08c880a3
MD
392 SCM_SET_CELL_TYPE (obj, scm_tc_free_cell);
393 free_struct_data (vtable_data, data);
394 }
395 }
396 }
d2e53ed6 397 while (!scm_is_null (newchain));
08c880a3
MD
398 return 0;
399}
400
a1ec6916 401SCM_DEFINE (scm_make_struct, "make-struct", 2, 0, 1,
1bbd0b84 402 (SCM vtable, SCM tail_array_size, SCM init),
b380b885 403 "Create a new structure.\n\n"
1bee0e70 404 "@var{type} must be a vtable structure (@pxref{Vtables}).\n\n"
b380b885
MD
405 "@var{tail-elts} must be a non-negative integer. If the layout\n"
406 "specification indicated by @var{type} includes a tail-array,\n"
407 "this is the number of elements allocated to that array.\n\n"
6386e25c 408 "The @var{init1}, @dots{} are optional arguments describing how\n"
04323af4
MD
409 "successive fields of the structure should be initialized. Only fields\n"
410 "with protection 'r' or 'w' can be initialized, except for fields of\n"
411 "type 's', which are automatically initialized to point to the new\n"
412 "structure itself; fields with protection 'o' can not be initialized by\n"
413 "Scheme programs.\n\n"
414 "If fewer optional arguments than initializable fields are supplied,\n"
415 "fields of type 'p' get default value #f while fields of type 'u' are\n"
416 "initialized to 0.\n\n"
417 "Structs are currently the basic representation for record-like data\n"
418 "structures in Guile. The plan is to eventually replace them with a\n"
419 "new representation which will at the same time be easier to use and\n"
420 "more powerful.\n\n"
6386e25c 421 "For more information, see the documentation for @code{make-vtable-vtable}.")
1bbd0b84 422#define FUNC_NAME s_scm_make_struct
0f2d19dd
JB
423{
424 SCM layout;
a55c2b68
MV
425 size_t basic_size;
426 size_t tail_elts;
92c2555f 427 scm_t_bits * data;
0f2d19dd
JB
428 SCM handle;
429
34d19ef6 430 SCM_VALIDATE_VTABLE (1, vtable);
af45e3b0 431 SCM_VALIDATE_REST_ARGUMENT (init);
0f2d19dd 432
d8c40b9f 433 layout = SCM_PACK (SCM_STRUCT_DATA (vtable) [scm_vtable_index_layout]);
cc95e00a 434 basic_size = scm_i_symbol_length (layout) / 2;
a55c2b68 435 tail_elts = scm_to_size_t (tail_array_size);
651f2cd2
KR
436
437 /* A tail array is only allowed if the layout fields string ends in "R",
438 "W" or "O". */
439 if (tail_elts != 0)
440 {
441 SCM layout_str, last_char;
442
443 if (basic_size == 0)
444 {
445 bad_tail:
446 SCM_MISC_ERROR ("tail array not allowed unless layout ends R, W, or O", SCM_EOL);
447 }
448
449 layout_str = scm_symbol_to_string (layout);
450 last_char = scm_string_ref (layout_str,
451 scm_from_size_t (2 * basic_size - 1));
452 if (! SCM_LAYOUT_TAILP (SCM_CHAR (last_char)))
453 goto bad_tail;
454 }
cb823e63
LC
455
456 /* In guile 1.8.5 and earlier, everything below was covered by a
457 CRITICAL_SECTION lock. This can lead to deadlocks in garbage
458 collection, since other threads might be holding the heap_mutex, while
459 sleeping on the CRITICAL_SECTION lock. There does not seem to be any
460 need for a lock on the section below, as it does not access or update
461 any globals, so the critical section has been removed. */
462
d8c40b9f 463 if (SCM_STRUCT_DATA (vtable)[scm_struct_i_flags] & SCM_STRUCTF_ENTITY)
a5bfe84d
MD
464 {
465 data = scm_alloc_struct (basic_size + tail_elts,
98d5f601 466 scm_struct_entity_n_extra_words,
4c9419ac 467 "entity struct");
c8045e8d
DH
468 data[scm_struct_i_procedure] = SCM_UNPACK (SCM_BOOL_F);
469 data[scm_struct_i_setter] = SCM_UNPACK (SCM_BOOL_F);
a5bfe84d
MD
470 }
471 else
472 data = scm_alloc_struct (basic_size + tail_elts,
473 scm_struct_n_extra_words,
4c9419ac 474 "struct");
228a24ef
DH
475 handle = scm_double_cell ((((scm_t_bits) SCM_STRUCT_DATA (vtable))
476 + scm_tc3_struct),
477 (scm_t_bits) data, 0, 0);
cb823e63 478
651f2cd2
KR
479 scm_struct_init (handle, layout, data, tail_elts, init);
480
0f2d19dd
JB
481 return handle;
482}
1bbd0b84 483#undef FUNC_NAME
0f2d19dd
JB
484
485
486
a1ec6916 487SCM_DEFINE (scm_make_vtable_vtable, "make-vtable-vtable", 2, 0, 1,
04323af4 488 (SCM user_fields, SCM tail_array_size, SCM init),
b380b885 489 "Return a new, self-describing vtable structure.\n\n"
04323af4
MD
490 "@var{user-fields} is a string describing user defined fields of the\n"
491 "vtable beginning at index @code{vtable-offset-user}\n"
492 "(see @code{make-struct-layout}).\n\n"
b380b885
MD
493 "@var{tail-size} specifies the size of the tail-array (if any) of\n"
494 "this vtable.\n\n"
6386e25c 495 "@var{init1}, @dots{} are the optional initializers for the fields of\n"
04323af4
MD
496 "the vtable.\n\n"
497 "Vtables have one initializable system field---the struct printer.\n"
498 "This field comes before the user fields in the initializers passed\n"
499 "to @code{make-vtable-vtable} and @code{make-struct}, and thus works as\n"
500 "a third optional argument to @code{make-vtable-vtable} and a fourth to\n"
501 "@code{make-struct} when creating vtables:\n\n"
502 "If the value is a procedure, it will be called instead of the standard\n"
503 "printer whenever a struct described by this vtable is printed.\n"
504 "The procedure will be called with arguments STRUCT and PORT.\n\n"
505 "The structure of a struct is described by a vtable, so the vtable is\n"
506 "in essence the type of the struct. The vtable is itself a struct with\n"
507 "a vtable. This could go on forever if it weren't for the\n"
29b4f9fb 508 "vtable-vtables which are self-describing vtables, and thus terminate\n"
04323af4
MD
509 "the chain.\n\n"
510 "There are several potential ways of using structs, but the standard\n"
511 "one is to use three kinds of structs, together building up a type\n"
512 "sub-system: one vtable-vtable working as the root and one or several\n"
513 "\"types\", each with a set of \"instances\". (The vtable-vtable should be\n"
29b4f9fb 514 "compared to the class <class> which is the class of itself.)\n\n"
1e6808ea 515 "@lisp\n"
04323af4
MD
516 "(define ball-root (make-vtable-vtable \"pr\" 0))\n\n"
517 "(define (make-ball-type ball-color)\n"
518 " (make-struct ball-root 0\n"
519 " (make-struct-layout \"pw\")\n"
520 " (lambda (ball port)\n"
521 " (format port \"#<a ~A ball owned by ~A>\"\n"
522 " (color ball)\n"
523 " (owner ball)))\n"
524 " ball-color))\n"
525 "(define (color ball) (struct-ref (struct-vtable ball) vtable-offset-user))\n"
526 "(define (owner ball) (struct-ref ball 0))\n\n"
527 "(define red (make-ball-type 'red))\n"
528 "(define green (make-ball-type 'green))\n\n"
529 "(define (make-ball type owner) (make-struct type 0 owner))\n\n"
530 "(define ball (make-ball green 'Nisse))\n"
531 "ball @result{} #<a green ball owned by Nisse>\n"
9401323e 532 "@end lisp")
1bbd0b84 533#define FUNC_NAME s_scm_make_vtable_vtable
0f2d19dd
JB
534{
535 SCM fields;
536 SCM layout;
a55c2b68
MV
537 size_t basic_size;
538 size_t tail_elts;
539 scm_t_bits *data;
0f2d19dd
JB
540 SCM handle;
541
d1ca2c64 542 SCM_VALIDATE_STRING (1, user_fields);
af45e3b0 543 SCM_VALIDATE_REST_ARGUMENT (init);
0f2d19dd 544
1afff620
KN
545 fields = scm_string_append (scm_list_2 (required_vtable_fields,
546 user_fields));
0f2d19dd 547 layout = scm_make_struct_layout (fields);
cc95e00a 548 basic_size = scm_i_symbol_length (layout) / 2;
a55c2b68 549 tail_elts = scm_to_size_t (tail_array_size);
9de87eea 550 SCM_CRITICAL_SECTION_START;
a5bfe84d
MD
551 data = scm_alloc_struct (basic_size + tail_elts,
552 scm_struct_n_extra_words,
4c9419ac 553 "struct");
228a24ef
DH
554 handle = scm_double_cell ((scm_t_bits) data + scm_tc3_struct,
555 (scm_t_bits) data, 0, 0);
f7620510
DH
556 data [scm_vtable_index_layout] = SCM_UNPACK (layout);
557 scm_struct_init (handle, layout, data, tail_elts, scm_cons (layout, init));
9de87eea 558 SCM_CRITICAL_SECTION_END;
0f2d19dd
JB
559 return handle;
560}
1bbd0b84 561#undef FUNC_NAME
0f2d19dd 562
d15ad007 563
651f2cd2
KR
564static SCM scm_i_vtable_vtable_no_extra_fields;
565
566SCM_DEFINE (scm_make_vtable, "make-vtable", 1, 1, 0,
567 (SCM fields, SCM printer),
568 "Create a vtable, for creating structures with the given\n"
569 "@var{fields}.\n"
570 "\n"
571 "The optional @var{printer} argument is a function to be called\n"
572 "@code{(@var{printer} struct port)} on the structures created.\n"
573 "It should look at @var{struct} and write to @var{port}.")
574#define FUNC_NAME s_scm_make_vtable
575{
576 if (SCM_UNBNDP (printer))
577 printer = SCM_BOOL_F;
578
579 return scm_make_struct (scm_i_vtable_vtable_no_extra_fields, SCM_INUM0,
580 scm_list_2 (scm_make_struct_layout (fields),
581 printer));
582}
583#undef FUNC_NAME
584
585
d15ad007
LC
586/* Return true if S1 and S2 are equal structures, i.e., if their vtable and
587 contents are the same. Field protections are honored. Thus, it is an
588 error to test the equality of structures that contain opaque fields. */
589SCM
590scm_i_struct_equalp (SCM s1, SCM s2)
591#define FUNC_NAME "scm_i_struct_equalp"
592{
593 SCM vtable1, vtable2, layout;
594 size_t struct_size, field_num;
595
596 SCM_VALIDATE_STRUCT (1, s1);
597 SCM_VALIDATE_STRUCT (2, s2);
598
599 vtable1 = SCM_STRUCT_VTABLE (s1);
600 vtable2 = SCM_STRUCT_VTABLE (s2);
601
602 if (!scm_is_eq (vtable1, vtable2))
603 return SCM_BOOL_F;
604
605 layout = SCM_STRUCT_LAYOUT (s1);
606 struct_size = scm_i_symbol_length (layout) / 2;
607
608 for (field_num = 0; field_num < struct_size; field_num++)
609 {
610 SCM s_field_num;
611 SCM field1, field2;
612
613 /* We have to use `scm_struct_ref ()' here so that fields are accessed
614 consistently, notably wrt. field types and access rights. */
615 s_field_num = scm_from_size_t (field_num);
616 field1 = scm_struct_ref (s1, s_field_num);
617 field2 = scm_struct_ref (s2, s_field_num);
618
42ddb3cb
LC
619 /* Self-referencing fields (type `s') must be skipped to avoid infinite
620 recursion. */
621 if (!(scm_is_eq (field1, s1) && (scm_is_eq (field2, s2))))
622 if (scm_is_false (scm_equal_p (field1, field2)))
623 return SCM_BOOL_F;
d15ad007
LC
624 }
625
42ddb3cb
LC
626 /* FIXME: Tail elements should be tested for equality. */
627
d15ad007
LC
628 return SCM_BOOL_T;
629}
630#undef FUNC_NAME
631
632
0f2d19dd
JB
633\f
634
635
a1ec6916 636SCM_DEFINE (scm_struct_ref, "struct-ref", 2, 0, 0,
1bbd0b84 637 (SCM handle, SCM pos),
8f85c0c6 638 "@deffnx {Scheme Procedure} struct-set! struct n value\n"
b380b885
MD
639 "Access (or modify) the @var{n}th field of @var{struct}.\n\n"
640 "If the field is of type 'p', then it can be set to an arbitrary value.\n\n"
641 "If the field is of type 'u', then it can only be set to a non-negative\n"
642 "integer value small enough to fit in one machine word.")
1bbd0b84 643#define FUNC_NAME s_scm_struct_ref
0f2d19dd 644{
5e840c2e 645 SCM answer = SCM_UNDEFINED;
92c2555f 646 scm_t_bits * data;
0f2d19dd 647 SCM layout;
cc95e00a 648 size_t layout_len;
a55c2b68 649 size_t p;
92c2555f 650 scm_t_bits n_fields;
27646f41 651 scm_t_wchar field_type = 0;
0f2d19dd
JB
652
653
34d19ef6 654 SCM_VALIDATE_STRUCT (1, handle);
0f2d19dd
JB
655
656 layout = SCM_STRUCT_LAYOUT (handle);
657 data = SCM_STRUCT_DATA (handle);
a55c2b68 658 p = scm_to_size_t (pos);
0f2d19dd 659
cc95e00a 660 layout_len = scm_i_symbol_length (layout);
4650d115
AW
661 if (SCM_STRUCT_VTABLE_FLAGS (handle) & SCM_STRUCTF_LIGHT)
662 /* no extra words */
663 n_fields = layout_len / 2;
664 else
665 n_fields = data[scm_struct_i_n_words];
2c36c351 666
34d19ef6 667 SCM_ASSERT_RANGE(1, pos, p < n_fields);
0f2d19dd 668
cc95e00a 669 if (p * 2 < layout_len)
2c36c351 670 {
27646f41
MG
671 scm_t_wchar ref;
672 field_type = scm_i_symbol_ref (layout, p * 2);
673 ref = scm_i_symbol_ref (layout, p * 2 + 1);
2c36c351
MD
674 if ((ref != 'r') && (ref != 'w'))
675 {
676 if ((ref == 'R') || (ref == 'W'))
677 field_type = 'u';
678 else
1afff620 679 SCM_MISC_ERROR ("ref denied for field ~A", scm_list_1 (pos));
2c36c351
MD
680 }
681 }
27646f41
MG
682 else if (scm_i_symbol_ref (layout, layout_len - 1) != 'O')
683 field_type = scm_i_symbol_ref(layout, layout_len - 2);
2c36c351 684 else
1afff620 685 SCM_MISC_ERROR ("ref denied for field ~A", scm_list_1 (pos));
2c36c351 686
0f2d19dd
JB
687 switch (field_type)
688 {
689 case 'u':
b9bd8526 690 answer = scm_from_ulong (data[p]);
0f2d19dd
JB
691 break;
692
693#if 0
694 case 'i':
b9bd8526 695 answer = scm_from_long (data[p]);
0f2d19dd
JB
696 break;
697
698 case 'd':
f8de44c1 699 answer = scm_make_real (*((double *)&(data[p])));
0f2d19dd
JB
700 break;
701#endif
702
703 case 's':
704 case 'p':
d8c40b9f 705 answer = SCM_PACK (data[p]);
0f2d19dd
JB
706 break;
707
708
709 default:
2ade72d7 710 SCM_MISC_ERROR ("unrecognized field type: ~S",
1afff620 711 scm_list_1 (SCM_MAKE_CHAR (field_type)));
0f2d19dd
JB
712 }
713
714 return answer;
715}
1bbd0b84 716#undef FUNC_NAME
0f2d19dd
JB
717
718
a1ec6916 719SCM_DEFINE (scm_struct_set_x, "struct-set!", 3, 0, 0,
1bbd0b84 720 (SCM handle, SCM pos, SCM val),
e3239868
DH
721 "Set the slot of the structure @var{handle} with index @var{pos}\n"
722 "to @var{val}. Signal an error if the slot can not be written\n"
723 "to.")
1bbd0b84 724#define FUNC_NAME s_scm_struct_set_x
0f2d19dd 725{
92c2555f 726 scm_t_bits * data;
0f2d19dd 727 SCM layout;
cc95e00a 728 size_t layout_len;
a55c2b68 729 size_t p;
0f2d19dd 730 int n_fields;
27646f41 731 scm_t_wchar field_type = 0;
0f2d19dd 732
34d19ef6 733 SCM_VALIDATE_STRUCT (1, handle);
0f2d19dd
JB
734
735 layout = SCM_STRUCT_LAYOUT (handle);
736 data = SCM_STRUCT_DATA (handle);
a55c2b68 737 p = scm_to_size_t (pos);
0f2d19dd 738
cc95e00a 739 layout_len = scm_i_symbol_length (layout);
4650d115
AW
740 if (SCM_STRUCT_VTABLE_FLAGS (handle) & SCM_STRUCTF_LIGHT)
741 /* no extra words */
742 n_fields = layout_len / 2;
743 else
744 n_fields = data[scm_struct_i_n_words];
0f2d19dd 745
34d19ef6 746 SCM_ASSERT_RANGE (1, pos, p < n_fields);
0f2d19dd 747
cc95e00a 748 if (p * 2 < layout_len)
2c36c351 749 {
e51fe79c 750 char set_x;
27646f41
MG
751 field_type = scm_i_symbol_ref (layout, p * 2);
752 set_x = scm_i_symbol_ref (layout, p * 2 + 1);
2c36c351 753 if (set_x != 'w')
1afff620 754 SCM_MISC_ERROR ("set! denied for field ~A", scm_list_1 (pos));
2c36c351 755 }
27646f41
MG
756 else if (scm_i_symbol_ref (layout, layout_len - 1) == 'W')
757 field_type = scm_i_symbol_ref (layout, layout_len - 2);
2c36c351 758 else
1afff620 759 SCM_MISC_ERROR ("set! denied for field ~A", scm_list_1 (pos));
2c36c351 760
0f2d19dd
JB
761 switch (field_type)
762 {
763 case 'u':
d8c40b9f 764 data[p] = SCM_NUM2ULONG (3, val);
0f2d19dd
JB
765 break;
766
767#if 0
768 case 'i':
e4b265d8 769 data[p] = SCM_NUM2LONG (3, val);
0f2d19dd
JB
770 break;
771
772 case 'd':
773 *((double *)&(data[p])) = scm_num2dbl (val, (char *)SCM_ARG3);
774 break;
775#endif
776
777 case 'p':
d8c40b9f 778 data[p] = SCM_UNPACK (val);
0f2d19dd
JB
779 break;
780
781 case 's':
2ade72d7 782 SCM_MISC_ERROR ("self fields immutable", SCM_EOL);
0f2d19dd
JB
783
784 default:
2ade72d7 785 SCM_MISC_ERROR ("unrecognized field type: ~S",
1afff620 786 scm_list_1 (SCM_MAKE_CHAR (field_type)));
0f2d19dd
JB
787 }
788
789 return val;
790}
1bbd0b84 791#undef FUNC_NAME
0f2d19dd
JB
792
793
a1ec6916 794SCM_DEFINE (scm_struct_vtable, "struct-vtable", 1, 0, 0,
1bbd0b84 795 (SCM handle),
b380b885 796 "Return the vtable structure that describes the type of @var{struct}.")
1bbd0b84 797#define FUNC_NAME s_scm_struct_vtable
0f2d19dd 798{
34d19ef6 799 SCM_VALIDATE_STRUCT (1, handle);
0f2d19dd
JB
800 return SCM_STRUCT_VTABLE (handle);
801}
1bbd0b84 802#undef FUNC_NAME
0f2d19dd
JB
803
804
a1ec6916 805SCM_DEFINE (scm_struct_vtable_tag, "struct-vtable-tag", 1, 0, 0,
1bbd0b84 806 (SCM handle),
e3239868 807 "Return the vtable tag of the structure @var{handle}.")
1bbd0b84 808#define FUNC_NAME s_scm_struct_vtable_tag
0f2d19dd 809{
34d19ef6 810 SCM_VALIDATE_VTABLE (1, handle);
b9bd8526 811 return scm_from_ulong (((unsigned long)SCM_STRUCT_DATA (handle)) >> 3);
98d5f601 812}
1bbd0b84 813#undef FUNC_NAME
98d5f601
MD
814
815/* {Associating names and classes with vtables}
816 *
817 * The name of a vtable should probably be stored as a slot. This is
818 * a backward compatible solution until agreement has been achieved on
819 * how to associate names with vtables.
820 */
821
c014a02e
ML
822unsigned long
823scm_struct_ihashq (SCM obj, unsigned long n)
98d5f601 824{
ad196599
MD
825 /* The length of the hash table should be a relative prime it's not
826 necessary to shift down the address. */
f1267706 827 return SCM_UNPACK (obj) % n;
98d5f601
MD
828}
829
830SCM
831scm_struct_create_handle (SCM obj)
832{
833 SCM handle = scm_hash_fn_create_handle_x (scm_struct_table,
834 obj,
835 SCM_BOOL_F,
836 scm_struct_ihashq,
837 scm_sloppy_assq,
838 0);
7888309b 839 if (scm_is_false (SCM_CDR (handle)))
98d5f601
MD
840 SCM_SETCDR (handle, scm_cons (SCM_BOOL_F, SCM_BOOL_F));
841 return handle;
842}
843
a1ec6916 844SCM_DEFINE (scm_struct_vtable_name, "struct-vtable-name", 1, 0, 0,
1bbd0b84 845 (SCM vtable),
e3239868 846 "Return the name of the vtable @var{vtable}.")
1bbd0b84 847#define FUNC_NAME s_scm_struct_vtable_name
98d5f601 848{
34d19ef6 849 SCM_VALIDATE_VTABLE (1, vtable);
98d5f601
MD
850 return SCM_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable)));
851}
1bbd0b84 852#undef FUNC_NAME
98d5f601 853
a1ec6916 854SCM_DEFINE (scm_set_struct_vtable_name_x, "set-struct-vtable-name!", 2, 0, 0,
1bbd0b84 855 (SCM vtable, SCM name),
e3239868 856 "Set the name of the vtable @var{vtable} to @var{name}.")
1bbd0b84 857#define FUNC_NAME s_scm_set_struct_vtable_name_x
98d5f601 858{
34d19ef6
HWN
859 SCM_VALIDATE_VTABLE (1, vtable);
860 SCM_VALIDATE_SYMBOL (2, name);
98d5f601
MD
861 SCM_SET_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable)),
862 name);
863 return SCM_UNSPECIFIED;
0f2d19dd 864}
1bbd0b84 865#undef FUNC_NAME
0f2d19dd
JB
866
867
868\f
869
bafcafb2 870void
1bbd0b84 871scm_print_struct (SCM exp, SCM port, scm_print_state *pstate)
bafcafb2 872{
7888309b 873 if (scm_is_true (scm_procedure_p (SCM_STRUCT_PRINTER (exp))))
4bfdf158
MD
874 scm_printer_apply (SCM_STRUCT_PRINTER (exp), exp, port, pstate);
875 else
bafcafb2 876 {
a1ae1799
MD
877 SCM vtable = SCM_STRUCT_VTABLE (exp);
878 SCM name = scm_struct_vtable_name (vtable);
879 scm_puts ("#<", port);
7888309b 880 if (scm_is_true (name))
a1ae1799
MD
881 scm_display (name, port);
882 else
883 scm_puts ("struct", port);
884 scm_putc (' ', port);
0345e278 885 scm_uintprint (SCM_UNPACK (vtable), 16, port);
b7f3516f 886 scm_putc (':', port);
0345e278 887 scm_uintprint (SCM_UNPACK (exp), 16, port);
b7f3516f 888 scm_putc ('>', port);
bafcafb2 889 }
bafcafb2 890}
1cc91f1b 891
08c880a3
MD
892void
893scm_struct_prehistory ()
894{
ea5c9285 895 scm_i_structs_to_free = SCM_EOL;
b4a1358c 896 scm_c_hook_add (&scm_before_sweep_c_hook, scm_struct_gc_init, 0, 0);
569aa529
HWN
897 /* With lazy sweep GC, the point at which the entire heap is swept
898 is just before the mark phase. */
53af8255 899 scm_c_hook_add (&scm_before_mark_c_hook, scm_free_structs, 0, 0);
08c880a3
MD
900}
901
0f2d19dd
JB
902void
903scm_init_struct ()
0f2d19dd 904{
98d5f601 905 scm_struct_table
e11e83f3 906 = scm_permanent_object (scm_make_weak_key_hash_table (scm_from_int (31)));
cc95e00a 907 required_vtable_fields = scm_from_locale_string ("prsrpw");
0f2d19dd 908 scm_permanent_object (required_vtable_fields);
651f2cd2
KR
909
910 scm_i_vtable_vtable_no_extra_fields =
911 scm_permanent_object
912 (scm_make_vtable_vtable (scm_nullstr, SCM_INUM0, SCM_EOL));
913
e11e83f3
MV
914 scm_c_define ("vtable-index-layout", scm_from_int (scm_vtable_index_layout));
915 scm_c_define ("vtable-index-vtable", scm_from_int (scm_vtable_index_vtable));
86d31dfe 916 scm_c_define ("vtable-index-printer",
e11e83f3
MV
917 scm_from_int (scm_vtable_index_printer));
918 scm_c_define ("vtable-offset-user", scm_from_int (scm_vtable_offset_user));
a0599745 919#include "libguile/struct.x"
0f2d19dd 920}
89e00824
ML
921
922/*
923 Local Variables:
924 c-file-style: "gnu"
925 End:
926*/