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