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