Mercurial > hg > xemacs-beta
comparison src/lrecord.h @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | a5df635868b2 |
comparison
equal
deleted
inserted
replaced
427:0a0253eac470 | 428:3ecd8885ac67 |
---|---|
1 /* The "lrecord" structure (header of a compound lisp object). | |
2 Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. | |
3 Copyright (C) 1996 Ben Wing. | |
4 | |
5 This file is part of XEmacs. | |
6 | |
7 XEmacs is free software; you can redistribute it and/or modify it | |
8 under the terms of the GNU General Public License as published by the | |
9 Free Software Foundation; either version 2, or (at your option) any | |
10 later version. | |
11 | |
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
18 along with XEmacs; see the file COPYING. If not, write to | |
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
20 Boston, MA 02111-1307, USA. */ | |
21 | |
22 /* Synched up with: Not in FSF. */ | |
23 | |
24 #ifndef _XEMACS_LRECORD_H_ | |
25 #define _XEMACS_LRECORD_H_ | |
26 | |
27 /* The "lrecord" type of Lisp object is used for all object types | |
28 other than a few simple ones. This allows many types to be | |
29 implemented but only a few bits required in a Lisp object for | |
30 type information. (The tradeoff is that each object has its | |
31 type marked in it, thereby increasing its size.) The first | |
32 four bytes of all lrecords is either a pointer to a struct | |
33 lrecord_implementation, which contains methods describing how | |
34 to process this object, or an index into an array of pointers | |
35 to struct lrecord_implementations plus some other data bits. | |
36 | |
37 Lrecords are of two types: straight lrecords, and lcrecords. | |
38 Straight lrecords are used for those types of objects that have | |
39 their own allocation routines (typically allocated out of 2K chunks | |
40 of memory called `frob blocks'). These objects have a `struct | |
41 lrecord_header' at the top, containing only the bits needed to find | |
42 the lrecord_implementation for the object. There are special | |
43 routines in alloc.c to deal with each such object type. | |
44 | |
45 Lcrecords are used for less common sorts of objects that don't | |
46 do their own allocation. Each such object is malloc()ed | |
47 individually, and the objects are chained together through | |
48 a `next' pointer. Lcrecords have a `struct lcrecord_header' | |
49 at the top, which contains a `struct lrecord_header' and | |
50 a `next' pointer, and are allocated using alloc_lcrecord(). | |
51 | |
52 Creating a new lcrecord type is fairly easy; just follow the | |
53 lead of some existing type (e.g. hash tables). Note that you | |
54 do not need to supply all the methods (see below); reasonable | |
55 defaults are provided for many of them. Alternatively, if you're | |
56 just looking for a way of encapsulating data (which possibly | |
57 could contain Lisp_Objects in it), you may well be able to use | |
58 the opaque type. */ | |
59 | |
60 struct lrecord_header | |
61 { | |
62 /* index into lrecord_implementations_table[] */ | |
63 unsigned type :8; | |
64 /* 1 if the object is marked during GC. */ | |
65 unsigned mark :1; | |
66 /* 1 if the object resides in read-only space */ | |
67 unsigned c_readonly : 1; | |
68 /* 1 if the object is readonly from lisp */ | |
69 unsigned lisp_readonly : 1; | |
70 }; | |
71 | |
72 struct lrecord_implementation; | |
73 int lrecord_type_index (CONST struct lrecord_implementation *implementation); | |
74 | |
75 # define set_lheader_implementation(header,imp) do { \ | |
76 struct lrecord_header* SLI_header = (header); \ | |
77 (SLI_header)->type = lrecord_type_index (imp); \ | |
78 (SLI_header)->mark = 0; \ | |
79 (SLI_header)->c_readonly = 0; \ | |
80 (SLI_header)->lisp_readonly = 0; \ | |
81 } while (0) | |
82 | |
83 struct lcrecord_header | |
84 { | |
85 struct lrecord_header lheader; | |
86 | |
87 /* The `next' field is normally used to chain all lrecords together | |
88 so that the GC can find (and free) all of them. | |
89 `alloc_lcrecord' threads records together. | |
90 | |
91 The `next' field may be used for other purposes as long as some | |
92 other mechanism is provided for letting the GC do its work. | |
93 | |
94 For example, the event and marker object types allocate members | |
95 out of memory chunks, and are able to find all unmarked members | |
96 by sweeping through the elements of the list of chunks. */ | |
97 struct lcrecord_header *next; | |
98 | |
99 /* The `uid' field is just for debugging/printing convenience. | |
100 Having this slot doesn't hurt us much spacewise, since an | |
101 lcrecord already has the above slots plus malloc overhead. */ | |
102 unsigned int uid :31; | |
103 | |
104 /* The `free' field is a flag that indicates whether this lcrecord | |
105 is on a "free list". Free lists are used to minimize the number | |
106 of calls to malloc() when we're repeatedly allocating and freeing | |
107 a number of the same sort of lcrecord. Lcrecords on a free list | |
108 always get marked in a different fashion, so we can use this flag | |
109 as a sanity check to make sure that free lists only have freed | |
110 lcrecords and there are no freed lcrecords elsewhere. */ | |
111 unsigned int free :1; | |
112 }; | |
113 | |
114 /* Used for lcrecords in an lcrecord-list. */ | |
115 struct free_lcrecord_header | |
116 { | |
117 struct lcrecord_header lcheader; | |
118 Lisp_Object chain; | |
119 }; | |
120 | |
121 /* see alloc.c for an explanation */ | |
122 Lisp_Object this_one_is_unmarkable (Lisp_Object obj); | |
123 | |
124 struct lrecord_implementation | |
125 { | |
126 CONST char *name; | |
127 /* This function is called at GC time, to make sure that all Lisp_Objects | |
128 pointed to by this object get properly marked. It should call | |
129 the mark_object function on all Lisp_Objects in the object. If | |
130 the return value is non-nil, it should be a Lisp_Object to be | |
131 marked (don't call the mark_object function explicitly on it, | |
132 because the GC routines will do this). Doing it this way reduces | |
133 recursion, so the object returned should preferably be the one | |
134 with the deepest level of Lisp_Object pointers. This function | |
135 can be NULL, meaning no GC marking is necessary. */ | |
136 Lisp_Object (*marker) (Lisp_Object); | |
137 /* This can be NULL if the object is an lcrecord; the | |
138 default_object_printer() in print.c will be used. */ | |
139 void (*printer) (Lisp_Object, Lisp_Object printcharfun, int escapeflag); | |
140 /* This function is called at GC time when the object is about to | |
141 be freed, and at dump time (FOR_DISKSAVE will be non-zero in this | |
142 case). It should perform any necessary cleanup (e.g. freeing | |
143 malloc()ed memory. This can be NULL, meaning no special | |
144 finalization is necessary. | |
145 | |
146 WARNING: remember that the finalizer is called at dump time even | |
147 though the object is not being freed. */ | |
148 void (*finalizer) (void *header, int for_disksave); | |
149 /* This can be NULL, meaning compare objects with EQ(). */ | |
150 int (*equal) (Lisp_Object obj1, Lisp_Object obj2, int depth); | |
151 /* This can be NULL, meaning use the Lisp_Object itself as the hash; | |
152 but *only* if the `equal' function is EQ (if two objects are | |
153 `equal', they *must* hash to the same value or the hashing won't | |
154 work). */ | |
155 unsigned long (*hash) (Lisp_Object, int); | |
156 | |
157 /* External data layout description */ | |
158 const struct lrecord_description *description; | |
159 | |
160 Lisp_Object (*getprop) (Lisp_Object obj, Lisp_Object prop); | |
161 int (*putprop) (Lisp_Object obj, Lisp_Object prop, Lisp_Object val); | |
162 int (*remprop) (Lisp_Object obj, Lisp_Object prop); | |
163 Lisp_Object (*plist) (Lisp_Object obj); | |
164 | |
165 /* Only one of these is non-0. If both are 0, it means that this type | |
166 is not instantiable by alloc_lcrecord(). */ | |
167 size_t static_size; | |
168 size_t (*size_in_bytes_method) (CONST void *header); | |
169 /* A unique subtag-code (dynamically) assigned to this datatype. */ | |
170 /* (This is a pointer so the rest of this structure can be read-only.) */ | |
171 int *lrecord_type_index; | |
172 /* A "basic" lrecord is any lrecord that's not an lcrecord, i.e. | |
173 one that does not have an lcrecord_header at the front and which | |
174 is (usually) allocated in frob blocks. We only use this flag for | |
175 some consistency checking, and that only when error-checking is | |
176 enabled. */ | |
177 int basic_p; | |
178 }; | |
179 | |
180 extern CONST struct lrecord_implementation *lrecord_implementations_table[]; | |
181 | |
182 #define XRECORD_LHEADER_IMPLEMENTATION(obj) \ | |
183 (lrecord_implementations_table[XRECORD_LHEADER (obj)->type]) | |
184 #define LHEADER_IMPLEMENTATION(lh) (lrecord_implementations_table[(lh)->type]) | |
185 | |
186 extern int gc_in_progress; | |
187 | |
188 #define MARKED_RECORD_P(obj) (gc_in_progress && XRECORD_LHEADER (obj)->mark) | |
189 #define MARKED_RECORD_HEADER_P(lheader) ((lheader)->mark) | |
190 #define MARK_RECORD_HEADER(lheader) ((void) ((lheader)->mark = 1)) | |
191 #define UNMARK_RECORD_HEADER(lheader) ((void) ((lheader)->mark = 0)) | |
192 | |
193 #define UNMARKABLE_RECORD_HEADER_P(lheader) \ | |
194 (LHEADER_IMPLEMENTATION (lheader)->marker == this_one_is_unmarkable) | |
195 | |
196 #define C_READONLY_RECORD_HEADER_P(lheader) ((lheader)->c_readonly) | |
197 #define LISP_READONLY_RECORD_HEADER_P(lheader) ((lheader)->lisp_readonly) | |
198 #define SET_C_READONLY_RECORD_HEADER(lheader) \ | |
199 ((void) ((lheader)->c_readonly = (lheader)->lisp_readonly = 1)) | |
200 #define SET_LISP_READONLY_RECORD_HEADER(lheader) \ | |
201 ((void) ((lheader)->lisp_readonly = 1)) | |
202 | |
203 /* External description stuff | |
204 | |
205 A lrecord external description is an array of values. The first | |
206 value of each line is a type, the second the offset in the lrecord | |
207 structure. Following values are parameters, their presence, type | |
208 and number is type-dependant. | |
209 | |
210 The description ends with a "XD_END" or "XD_SPECIFIER_END" record. | |
211 | |
212 Some example descriptions : | |
213 static const struct lrecord_description cons_description[] = { | |
214 { XD_LISP_OBJECT, offsetof(struct Lisp_Cons, car), 2 }, | |
215 { XD_END } | |
216 }; | |
217 | |
218 Which means "two lisp objects starting at the 'car' element" | |
219 | |
220 static const struct lrecord_description string_description[] = { | |
221 { XD_BYTECOUNT, offsetof(Lisp_String, size) }, | |
222 { XD_OPAQUE_DATA_PTR, offsetof(Lisp_String, data), XD_INDIRECT(0, 1) }, | |
223 { XD_LISP_OBJECT, offsetof(Lisp_String, plist), 1 }, | |
224 { XD_END } | |
225 }; | |
226 "A pointer to string data at 'data', the size of the pointed array being the value | |
227 of the size variable plus 1, and one lisp object at 'plist'" | |
228 | |
229 The existing types : | |
230 XD_LISP_OBJECT | |
231 Lisp objects. The third element is the count. This is also the type to use | |
232 for pointers to other lrecords. | |
233 | |
234 XD_LO_RESET_NIL | |
235 Lisp objects which will be reset to Qnil when dumping. Useful for cleaning | |
236 up caches. | |
237 | |
238 XD_LO_LINK | |
239 Link in a linked list of objects of the same type. | |
240 | |
241 XD_OPAQUE_PTR | |
242 Pointer to undumpable data. Must be NULL when dumping. | |
243 | |
244 XD_STRUCT_PTR | |
245 Pointer to described struct. Parameters are number of structures and | |
246 struct_description. | |
247 | |
248 XD_OPAQUE_DATA_PTR | |
249 Pointer to dumpable opaque data. Parameter is the size of the data. | |
250 Pointed data must be relocatable without changes. | |
251 | |
252 XD_C_STRING | |
253 Pointer to a C string. | |
254 | |
255 XD_DOC_STRING | |
256 Pointer to a doc string (C string if positive, opaque value if negative) | |
257 | |
258 XD_INT_RESET | |
259 An integer which will be reset to a given value in the dump file. | |
260 | |
261 | |
262 XD_SIZE_T | |
263 size_t value. Used for counts. | |
264 | |
265 XD_INT | |
266 int value. Used for counts. | |
267 | |
268 XD_LONG | |
269 long value. Used for counts. | |
270 | |
271 XD_BYTECOUNT | |
272 bytecount value. Used for counts. | |
273 | |
274 XD_END | |
275 Special type indicating the end of the array. | |
276 | |
277 XD_SPECIFIER_END | |
278 Special type indicating the end of the array for a specifier. Extra | |
279 description is going to be fetched from the specifier methods. | |
280 | |
281 | |
282 Special macros: | |
283 XD_INDIRECT(line, delta) | |
284 Usable where a "count" or "size" is requested. Gives the value of | |
285 the element which is at line number 'line' in the description (count | |
286 starts at zero) and adds delta to it. | |
287 */ | |
288 | |
289 enum lrecord_description_type { | |
290 XD_LISP_OBJECT, | |
291 XD_LO_RESET_NIL, | |
292 XD_LO_LINK, | |
293 XD_OPAQUE_PTR, | |
294 XD_STRUCT_PTR, | |
295 XD_OPAQUE_DATA_PTR, | |
296 XD_C_STRING, | |
297 XD_DOC_STRING, | |
298 XD_INT_RESET, | |
299 XD_SIZE_T, | |
300 XD_INT, | |
301 XD_LONG, | |
302 XD_BYTECOUNT, | |
303 XD_END, | |
304 XD_SPECIFIER_END | |
305 }; | |
306 | |
307 struct lrecord_description { | |
308 enum lrecord_description_type type; | |
309 int offset; | |
310 EMACS_INT data1; | |
311 const struct struct_description *data2; | |
312 }; | |
313 | |
314 struct struct_description { | |
315 size_t size; | |
316 const struct lrecord_description *description; | |
317 }; | |
318 | |
319 #define XD_INDIRECT(val, delta) (-1-((val)|(delta<<8))) | |
320 | |
321 #define XD_IS_INDIRECT(code) (code<0) | |
322 #define XD_INDIRECT_VAL(code) ((-1-code) & 255) | |
323 #define XD_INDIRECT_DELTA(code) (((-1-code)>>8) & 255) | |
324 | |
325 #define XD_DYNARR_DESC(base_type, sub_desc) \ | |
326 { XD_STRUCT_PTR, offsetof(base_type, base), XD_INDIRECT(1, 0), sub_desc }, \ | |
327 { XD_INT, offsetof(base_type, cur) }, \ | |
328 { XD_INT_RESET, offsetof(base_type, max), XD_INDIRECT(1, 0) } | |
329 | |
330 /* Declaring the following structures as const puts them in the | |
331 text (read-only) segment, which makes debugging inconvenient | |
332 because this segment is not mapped when processing a core- | |
333 dump file */ | |
334 | |
335 #ifdef DEBUG_XEMACS | |
336 #define CONST_IF_NOT_DEBUG | |
337 #else | |
338 #define CONST_IF_NOT_DEBUG CONST | |
339 #endif | |
340 | |
341 /* DEFINE_LRECORD_IMPLEMENTATION is for objects with constant size. | |
342 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION is for objects whose size varies. | |
343 */ | |
344 | |
345 #if defined (ERROR_CHECK_TYPECHECK) | |
346 # define DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) | |
347 #else | |
348 # define DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) | |
349 #endif | |
350 | |
351 #define DEFINE_BASIC_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,structtype) \ | |
352 DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,structtype) | |
353 | |
354 #define DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,props,structtype) \ | |
355 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,props,sizeof(structtype),0,1,structtype) | |
356 | |
357 #define DEFINE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,structtype) \ | |
358 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,structtype) | |
359 | |
360 #define DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,props,structtype) \ | |
361 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,props,sizeof (structtype),0,0,structtype) | |
362 | |
363 #define DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,sizer,structtype) \ | |
364 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,sizer,structtype) | |
365 | |
366 #define DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,props,sizer,structtype) \ | |
367 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,props,0,sizer,0,structtype) \ | |
368 | |
369 #define MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,props,size,sizer,basic_p,structtype) \ | |
370 DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) \ | |
371 static int lrecord_##c_name##_lrecord_type_index; \ | |
372 CONST_IF_NOT_DEBUG struct lrecord_implementation lrecord_##c_name = \ | |
373 { name, marker, printer, nuker, equal, hash, desc, \ | |
374 getprop, putprop, remprop, props, size, sizer, \ | |
375 &(lrecord_##c_name##_lrecord_type_index), basic_p } \ | |
376 | |
377 #define LRECORDP(a) (XTYPE (a) == Lisp_Type_Record) | |
378 #define XRECORD_LHEADER(a) ((struct lrecord_header *) XPNTR (a)) | |
379 | |
380 #define RECORD_TYPEP(x, ty) \ | |
381 (LRECORDP (x) && \ | |
382 lrecord_implementations_table[XRECORD_LHEADER (x)->type] == (ty)) | |
383 | |
384 /* NOTE: the DECLARE_LRECORD() must come before the associated | |
385 DEFINE_LRECORD_*() or you will get compile errors. | |
386 | |
387 Furthermore, you always need to put the DECLARE_LRECORD() in a header | |
388 file, and make sure the header file is included in inline.c, even | |
389 if the type is private to a particular file. Otherwise, you will | |
390 get undefined references for the error_check_foo() inline function | |
391 under GCC. */ | |
392 | |
393 #ifdef ERROR_CHECK_TYPECHECK | |
394 | |
395 # define DECLARE_LRECORD(c_name, structtype) \ | |
396 extern CONST_IF_NOT_DEBUG struct lrecord_implementation \ | |
397 lrecord_##c_name; \ | |
398 INLINE structtype *error_check_##c_name (Lisp_Object obj); \ | |
399 INLINE structtype * \ | |
400 error_check_##c_name (Lisp_Object obj) \ | |
401 { \ | |
402 assert (RECORD_TYPEP (obj, &lrecord_##c_name)); \ | |
403 return (structtype *) XPNTR (obj); \ | |
404 } \ | |
405 extern Lisp_Object Q##c_name##p | |
406 | |
407 # define DECLARE_NONRECORD(c_name, type_enum, structtype) \ | |
408 INLINE structtype *error_check_##c_name (Lisp_Object obj); \ | |
409 INLINE structtype * \ | |
410 error_check_##c_name (Lisp_Object obj) \ | |
411 { \ | |
412 assert (XTYPE (obj) == type_enum); \ | |
413 return (structtype *) XPNTR (obj); \ | |
414 } \ | |
415 extern Lisp_Object Q##c_name##p | |
416 | |
417 # define XRECORD(x, c_name, structtype) error_check_##c_name (x) | |
418 # define XNONRECORD(x, c_name, type_enum, structtype) error_check_##c_name (x) | |
419 | |
420 # define XSETRECORD(var, p, c_name) do \ | |
421 { \ | |
422 XSETOBJ (var, Lisp_Type_Record, p); \ | |
423 assert (RECORD_TYPEP (var, &lrecord_##c_name)); \ | |
424 } while (0) | |
425 | |
426 #else /* not ERROR_CHECK_TYPECHECK */ | |
427 | |
428 # define DECLARE_LRECORD(c_name, structtype) \ | |
429 extern Lisp_Object Q##c_name##p; \ | |
430 extern CONST_IF_NOT_DEBUG struct lrecord_implementation \ | |
431 lrecord_##c_name | |
432 # define DECLARE_NONRECORD(c_name, type_enum, structtype) \ | |
433 extern Lisp_Object Q##c_name##p | |
434 # define XRECORD(x, c_name, structtype) ((structtype *) XPNTR (x)) | |
435 # define XNONRECORD(x, c_name, type_enum, structtype) \ | |
436 ((structtype *) XPNTR (x)) | |
437 # define XSETRECORD(var, p, c_name) XSETOBJ (var, Lisp_Type_Record, p) | |
438 | |
439 #endif /* not ERROR_CHECK_TYPECHECK */ | |
440 | |
441 #define RECORDP(x, c_name) RECORD_TYPEP (x, &lrecord_##c_name) | |
442 | |
443 /* Note: we now have two different kinds of type-checking macros. | |
444 The "old" kind has now been renamed CONCHECK_foo. The reason for | |
445 this is that the CONCHECK_foo macros signal a continuable error, | |
446 allowing the user (through debug-on-error) to substitute a different | |
447 value and return from the signal, which causes the lvalue argument | |
448 to get changed. Quite a lot of code would crash if that happened, | |
449 because it did things like | |
450 | |
451 foo = XCAR (list); | |
452 CHECK_STRING (foo); | |
453 | |
454 and later on did XSTRING (XCAR (list)), assuming that the type | |
455 is correct (when it might be wrong, if the user substituted a | |
456 correct value in the debugger). | |
457 | |
458 To get around this, I made all the CHECK_foo macros signal a | |
459 non-continuable error. Places where a continuable error is OK | |
460 (generally only when called directly on the argument of a Lisp | |
461 primitive) should be changed to use CONCHECK(). | |
462 | |
463 FSF Emacs does not have this problem because RMS took the cheesy | |
464 way out and disabled returning from a signal entirely. */ | |
465 | |
466 #define CONCHECK_RECORD(x, c_name) do { \ | |
467 if (!RECORD_TYPEP (x, &lrecord_##c_name)) \ | |
468 x = wrong_type_argument (Q##c_name##p, x); \ | |
469 } while (0) | |
470 #define CONCHECK_NONRECORD(x, lisp_enum, predicate) do {\ | |
471 if (XTYPE (x) != lisp_enum) \ | |
472 x = wrong_type_argument (predicate, x); \ | |
473 } while (0) | |
474 #define CHECK_RECORD(x, c_name) do { \ | |
475 if (!RECORD_TYPEP (x, &lrecord_##c_name)) \ | |
476 dead_wrong_type_argument (Q##c_name##p, x); \ | |
477 } while (0) | |
478 #define CHECK_NONRECORD(x, lisp_enum, predicate) do { \ | |
479 if (XTYPE (x) != lisp_enum) \ | |
480 dead_wrong_type_argument (predicate, x); \ | |
481 } while (0) | |
482 | |
483 void *alloc_lcrecord (size_t size, CONST struct lrecord_implementation *); | |
484 | |
485 #define alloc_lcrecord_type(type, lrecord_implementation) \ | |
486 ((type *) alloc_lcrecord (sizeof (type), lrecord_implementation)) | |
487 | |
488 /* Copy the data from one lcrecord structure into another, but don't | |
489 overwrite the header information. */ | |
490 | |
491 #define copy_lcrecord(dst, src) \ | |
492 memcpy ((char *) dst + sizeof (struct lcrecord_header), \ | |
493 (char *) src + sizeof (struct lcrecord_header), \ | |
494 sizeof (*dst) - sizeof (struct lcrecord_header)) | |
495 | |
496 #define zero_lcrecord(lcr) \ | |
497 memset ((char *) lcr + sizeof (struct lcrecord_header), 0, \ | |
498 sizeof (*lcr) - sizeof (struct lcrecord_header)) | |
499 | |
500 #endif /* _XEMACS_LRECORD_H_ */ |