comparison src/lrecord.h @ 398:74fd4e045ea6 r21-2-29

Import from CVS: tag r21-2-29
author cvs
date Mon, 13 Aug 2007 11:13:30 +0200
parents 8626e4521993
children a86b2b5e0111
comparison
equal deleted inserted replaced
397:f4aeb21a5bad 398:74fd4e045ea6
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */ 20 Boston, MA 02111-1307, USA. */
21 21
22 /* Synched up with: Not in FSF. */ 22 /* Synched up with: Not in FSF. */
23 23
24 #ifndef _XEMACS_LRECORD_H_ 24 #ifndef INCLUDED_lrecord_h_
25 #define _XEMACS_LRECORD_H_ 25 #define INCLUDED_lrecord_h_
26 26
27 /* The "lrecord" type of Lisp object is used for all object types 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 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 29 implemented but only a few bits required in a Lisp object for type
30 type information. (The tradeoff is that each object has its 30 information. (The tradeoff is that each object has its type marked
31 type marked in it, thereby increasing its size.) The first 31 in it, thereby increasing its size.) All lrecords begin with a
32 four bytes of all lrecords is either a pointer to a struct 32 `struct lrecord_header', which identifies the lisp object type, by
33 lrecord_implementation, which contains methods describing how 33 providing an index into a table of `struct lrecord_implementation',
34 to process this object, or an index into an array of pointers 34 which describes the behavior of the lisp object. It also contains
35 to struct lrecord_implementations plus some other data bits. 35 some other data bits.
36 36
37 Lrecords are of two types: straight lrecords, and lcrecords. 37 Lrecords are of two types: straight lrecords, and lcrecords.
38 Straight lrecords are used for those types of objects that have 38 Straight lrecords are used for those types of objects that have
39 their own allocation routines (typically allocated out of 2K chunks 39 their own allocation routines (typically allocated out of 2K chunks
40 of memory called `frob blocks'). These objects have a `struct 40 of memory called `frob blocks'). These objects have a `struct
41 lrecord_header' at the top, containing only the bits needed to find 41 lrecord_header' at the top, containing only the bits needed to find
42 the lrecord_implementation for the object. There are special 42 the lrecord_implementation for the object. There are special
43 routines in alloc.c to deal with each such object type. 43 routines in alloc.c to deal with each such object type.
44 44
45 Lcrecords are used for less common sorts of objects that don't 45 Lcrecords are used for less common sorts of objects that don't do
46 do their own allocation. Each such object is malloc()ed 46 their own allocation. Each such object is malloc()ed individually,
47 individually, and the objects are chained together through 47 and the objects are chained together through a `next' pointer.
48 a `next' pointer. Lcrecords have a `struct lcrecord_header' 48 Lcrecords have a `struct lcrecord_header' at the top, which
49 at the top, which contains a `struct lrecord_header' and 49 contains a `struct lrecord_header' and a `next' pointer, and are
50 a `next' pointer, and are allocated using alloc_lcrecord(). 50 allocated using alloc_lcrecord().
51 51
52 Creating a new lcrecord type is fairly easy; just follow the 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 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 54 do not need to supply all the methods (see below); reasonable
55 defaults are provided for many of them. Alternatively, if you're 55 defaults are provided for many of them. Alternatively, if you're
57 could contain Lisp_Objects in it), you may well be able to use 57 could contain Lisp_Objects in it), you may well be able to use
58 the opaque type. */ 58 the opaque type. */
59 59
60 struct lrecord_header 60 struct lrecord_header
61 { 61 {
62 /* It would be better to put the mark-bit together with the
63 following datatype identification field in an 8- or 16-bit
64 integer rather than playing funny games with changing
65 header->implementation and "wasting" 32 bits on the below
66 pointer. The type-id would then be a 7 or 15 bit index into a
67 table of lrecord-implementations rather than a direct pointer.
68 There would be 24 (or 16) bits left over for datatype-specific
69 per-instance flags.
70
71 The below is the simplest thing to do for the present,
72 and doesn't incur that much overhead as most Emacs records
73 are of such a size that the overhead isn't too bad.
74 (The marker datatype is the worst case.)
75
76 It also has the very very very slight advantage that type-checking
77 involves one memory read (of the "implementation" slot) and a
78 comparison against a link-time constant address rather than a
79 read and a comparison against a variable value. (Variable since
80 it is a very good idea to assign the indices into the hypothetical
81 type-code table dynamically rather that pre-defining them.)
82 I think I remember that Elk Lisp does something like this.
83 Gee, I wonder if some cretin has patented it? */
84
85 /*
86 * If USE_INDEXED_LRECORD_IMPLEMENTATION is defined, we are
87 * implementing the scheme described in the 'It would be better
88 * ...' paragraph above.
89 */
90 #ifdef USE_INDEXED_LRECORD_IMPLEMENTATION
91 /* index into lrecord_implementations_table[] */ 62 /* index into lrecord_implementations_table[] */
92 unsigned char type; 63 unsigned int type :8;
93 /* 1 if the object is marked during GC, 0 otherwise. */ 64 /* 1 if the object is marked during GC. */
94 char mark; 65 unsigned int mark :1;
95 /* 1 if the object resides in pure (read-only) space */ 66 /* 1 if the object resides in read-only space */
96 char pure; 67 unsigned int c_readonly :1;
97 #else 68 /* 1 if the object is readonly from lisp */
98 CONST struct lrecord_implementation *implementation; 69 unsigned int lisp_readonly :1;
99 #endif
100 }; 70 };
101 71
102 struct lrecord_implementation; 72 struct lrecord_implementation;
103 int lrecord_type_index (CONST struct lrecord_implementation *implementation); 73 int lrecord_type_index (const struct lrecord_implementation *implementation);
104 74
105 #ifdef USE_INDEXED_LRECORD_IMPLEMENTATION 75 #define set_lheader_implementation(header,imp) do { \
106 # define set_lheader_implementation(header,imp) do { \
107 struct lrecord_header* SLI_header = (header); \ 76 struct lrecord_header* SLI_header = (header); \
108 (SLI_header)->type = lrecord_type_index (imp); \ 77 SLI_header->type = lrecord_type_index (imp); \
109 (SLI_header)->mark = 0; \ 78 SLI_header->mark = 0; \
110 (SLI_header)->pure = 0; \ 79 SLI_header->c_readonly = 0; \
80 SLI_header->lisp_readonly = 0; \
111 } while (0) 81 } while (0)
112 #else
113 # define set_lheader_implementation(header,imp) \
114 ((void) ((header)->implementation = (imp)))
115 #endif
116 82
117 struct lcrecord_header 83 struct lcrecord_header
118 { 84 {
119 struct lrecord_header lheader; 85 struct lrecord_header lheader;
120 86
121 /* The `next' field is normally used to chain all lrecords together 87 /* The `next' field is normally used to chain all lcrecords together
122 so that the GC can find (and free) all of them. 88 so that the GC can find (and free) all of them.
123 `alloc_lcrecord' threads records together. 89 `alloc_lcrecord' threads lcrecords together.
124 90
125 The `next' field may be used for other purposes as long as some 91 The `next' field may be used for other purposes as long as some
126 other mechanism is provided for letting the GC do its work. 92 other mechanism is provided for letting the GC do its work.
127 93
128 For example, the event and marker object types allocate members 94 For example, the event and marker object types allocate members
150 { 116 {
151 struct lcrecord_header lcheader; 117 struct lcrecord_header lcheader;
152 Lisp_Object chain; 118 Lisp_Object chain;
153 }; 119 };
154 120
155 /* This as the value of lheader->implementation->finalizer
156 means that this record is already marked */
157 void this_marks_a_marked_record (void *, int);
158
159 /* see alloc.c for an explanation */ 121 /* see alloc.c for an explanation */
160 Lisp_Object this_one_is_unmarkable (Lisp_Object obj, 122 Lisp_Object this_one_is_unmarkable (Lisp_Object obj);
161 void (*markobj) (Lisp_Object));
162 123
163 struct lrecord_implementation 124 struct lrecord_implementation
164 { 125 {
165 CONST char *name; 126 const char *name;
166 /* This function is called at GC time, to make sure that all Lisp_Objects 127
128 /* `marker' is called at GC time, to make sure that all Lisp_Objects
167 pointed to by this object get properly marked. It should call 129 pointed to by this object get properly marked. It should call
168 the mark_object function on all Lisp_Objects in the object. If 130 the mark_object function on all Lisp_Objects in the object. If
169 the return value is non-nil, it should be a Lisp_Object to be 131 the return value is non-nil, it should be a Lisp_Object to be
170 marked (don't call the mark_object function explicitly on it, 132 marked (don't call the mark_object function explicitly on it,
171 because the GC routines will do this). Doing it this way reduces 133 because the GC routines will do this). Doing it this way reduces
172 recursion, so the object returned should preferably be the one 134 recursion, so the object returned should preferably be the one
173 with the deepest level of Lisp_Object pointers. This function 135 with the deepest level of Lisp_Object pointers. This function
174 can be NULL, meaning no GC marking is necessary. */ 136 can be NULL, meaning no GC marking is necessary. */
175 Lisp_Object (*marker) (Lisp_Object, void (*mark_object) (Lisp_Object)); 137 Lisp_Object (*marker) (Lisp_Object);
176 /* This can be NULL if the object is an lcrecord; the 138
177 default_object_printer() in print.c will be used. */ 139 /* `printer' converts the object to a printed representation.
140 This can be NULL; in this case default_object_printer() will be
141 used instead. */
178 void (*printer) (Lisp_Object, Lisp_Object printcharfun, int escapeflag); 142 void (*printer) (Lisp_Object, Lisp_Object printcharfun, int escapeflag);
179 /* This function is called at GC time when the object is about to 143
144 /* `finalizer' is called at GC time when the object is about to
180 be freed, and at dump time (FOR_DISKSAVE will be non-zero in this 145 be freed, and at dump time (FOR_DISKSAVE will be non-zero in this
181 case). It should perform any necessary cleanup (e.g. freeing 146 case). It should perform any necessary cleanup (e.g. freeing
182 malloc()ed memory. This can be NULL, meaning no special 147 malloc()ed memory). This can be NULL, meaning no special
183 finalization is necessary. 148 finalization is necessary.
184 149
185 WARNING: remember that the finalizer is called at dump time even 150 WARNING: remember that `finalizer' is called at dump time even
186 though the object is not being freed. */ 151 though the object is not being freed. */
187 void (*finalizer) (void *header, int for_disksave); 152 void (*finalizer) (void *header, int for_disksave);
153
188 /* This can be NULL, meaning compare objects with EQ(). */ 154 /* This can be NULL, meaning compare objects with EQ(). */
189 int (*equal) (Lisp_Object obj1, Lisp_Object obj2, int depth); 155 int (*equal) (Lisp_Object obj1, Lisp_Object obj2, int depth);
190 /* This can be NULL, meaning use the Lisp_Object itself as the hash; 156
191 but *only* if the `equal' function is EQ (if two objects are 157 /* `hash' generates hash values for use with hash tables that have
192 `equal', they *must* hash to the same value or the hashing won't 158 `equal' as their test function. This can be NULL, meaning use
193 work). */ 159 the Lisp_Object itself as the hash. But, you must still satisfy
160 the constraint that if two objects are `equal', then they *must*
161 hash to the same value in order for hash tables to work properly.
162 This means that `hash' can be NULL only if the `equal' method is
163 also NULL. */
194 unsigned long (*hash) (Lisp_Object, int); 164 unsigned long (*hash) (Lisp_Object, int);
165
166 /* External data layout description */
167 const struct lrecord_description *description;
168
169 /* These functions allow any object type to have builtin property
170 lists that can be manipulated from the lisp level with
171 `get', `put', `remprop', and `object-plist'. */
195 Lisp_Object (*getprop) (Lisp_Object obj, Lisp_Object prop); 172 Lisp_Object (*getprop) (Lisp_Object obj, Lisp_Object prop);
196 int (*putprop) (Lisp_Object obj, Lisp_Object prop, Lisp_Object val); 173 int (*putprop) (Lisp_Object obj, Lisp_Object prop, Lisp_Object val);
197 int (*remprop) (Lisp_Object obj, Lisp_Object prop); 174 int (*remprop) (Lisp_Object obj, Lisp_Object prop);
198 Lisp_Object (*plist) (Lisp_Object obj); 175 Lisp_Object (*plist) (Lisp_Object obj);
199 176
200 /* Only one of these is non-0. If both are 0, it means that this type 177 /* Only one of `static_size' and `size_in_bytes_method' is non-0.
201 is not instantiable by alloc_lcrecord(). */ 178 If both are 0, this type is not instantiable by alloc_lcrecord(). */
202 size_t static_size; 179 size_t static_size;
203 size_t (*size_in_bytes_method) (CONST void *header); 180 size_t (*size_in_bytes_method) (const void *header);
181
204 /* A unique subtag-code (dynamically) assigned to this datatype. */ 182 /* A unique subtag-code (dynamically) assigned to this datatype. */
205 /* (This is a pointer so the rest of this structure can be read-only.) */ 183 /* (This is a pointer so the rest of this structure can be read-only.) */
206 int *lrecord_type_index; 184 int *lrecord_type_index;
185
207 /* A "basic" lrecord is any lrecord that's not an lcrecord, i.e. 186 /* A "basic" lrecord is any lrecord that's not an lcrecord, i.e.
208 one that does not have an lcrecord_header at the front and which 187 one that does not have an lcrecord_header at the front and which
209 is (usually) allocated in frob blocks. We only use this flag for 188 is (usually) allocated in frob blocks. We only use this flag for
210 some consistency checking, and that only when error-checking is 189 some consistency checking, and that only when error-checking is
211 enabled. */ 190 enabled. */
212 int basic_p; 191 unsigned int basic_p :1;
213 }; 192 };
214 193
215 #ifdef USE_INDEXED_LRECORD_IMPLEMENTATION 194 extern const struct lrecord_implementation *lrecord_implementations_table[];
216 extern CONST struct lrecord_implementation *lrecord_implementations_table[]; 195
217 196 #define XRECORD_LHEADER_IMPLEMENTATION(obj) \
218 # define XRECORD_LHEADER_IMPLEMENTATION(obj) \
219 (lrecord_implementations_table[XRECORD_LHEADER (obj)->type]) 197 (lrecord_implementations_table[XRECORD_LHEADER (obj)->type])
220 # define LHEADER_IMPLEMENTATION(lh) (lrecord_implementations_table[(lh)->type]) 198 #define LHEADER_IMPLEMENTATION(lh) (lrecord_implementations_table[(lh)->type])
221 #else
222 # define XRECORD_LHEADER_IMPLEMENTATION(obj) \
223 (XRECORD_LHEADER (obj)->implementation)
224 # define LHEADER_IMPLEMENTATION(lh) ((lh)->implementation)
225 #endif
226 199
227 extern int gc_in_progress; 200 extern int gc_in_progress;
228 201
229 #ifdef USE_INDEXED_LRECORD_IMPLEMENTATION 202 #define MARKED_RECORD_P(obj) (gc_in_progress && XRECORD_LHEADER (obj)->mark)
230 # define MARKED_RECORD_P(obj) (gc_in_progress && XRECORD_LHEADER (obj)->mark) 203 #define MARKED_RECORD_HEADER_P(lheader) ((lheader)->mark)
231 #else 204 #define MARK_RECORD_HEADER(lheader) ((void) ((lheader)->mark = 1))
232 # define MARKED_RECORD_P(obj) (gc_in_progress && \ 205 #define UNMARK_RECORD_HEADER(lheader) ((void) ((lheader)->mark = 0))
233 XRECORD_LHEADER (obj)->implementation->finalizer == \
234 this_marks_a_marked_record)
235 #endif
236
237 #ifdef USE_INDEXED_LRECORD_IMPLEMENTATION
238
239 # define MARKED_RECORD_HEADER_P(lheader) ((lheader)->mark)
240 # define MARK_RECORD_HEADER(lheader) ((void) ((lheader)->mark = 1))
241 # define UNMARK_RECORD_HEADER(lheader) ((void) ((lheader)->mark = 0))
242
243 #else /* ! USE_INDEXED_LRECORD_IMPLEMENTATION */
244
245 # define MARKED_RECORD_HEADER_P(lheader) \
246 ((lheader)->implementation->finalizer == this_marks_a_marked_record)
247 # define MARK_RECORD_HEADER(lheader) ((void) (((lheader)->implementation)++))
248 # define UNMARK_RECORD_HEADER(lheader) ((void) (((lheader)->implementation)--))
249
250 #endif /* ! USE_INDEXED_LRECORD_IMPLEMENTATION */
251 206
252 #define UNMARKABLE_RECORD_HEADER_P(lheader) \ 207 #define UNMARKABLE_RECORD_HEADER_P(lheader) \
253 (LHEADER_IMPLEMENTATION (lheader)->marker == this_one_is_unmarkable) 208 (LHEADER_IMPLEMENTATION (lheader)->marker == this_one_is_unmarkable)
209
210 #define C_READONLY_RECORD_HEADER_P(lheader) ((lheader)->c_readonly)
211 #define LISP_READONLY_RECORD_HEADER_P(lheader) ((lheader)->lisp_readonly)
212 #define SET_C_READONLY_RECORD_HEADER(lheader) \
213 ((void) ((lheader)->c_readonly = (lheader)->lisp_readonly = 1))
214 #define SET_LISP_READONLY_RECORD_HEADER(lheader) \
215 ((void) ((lheader)->lisp_readonly = 1))
216
217 /* External description stuff
218
219 A lrecord external description is an array of values. The first
220 value of each line is a type, the second the offset in the lrecord
221 structure. Following values are parameters, their presence, type
222 and number is type-dependant.
223
224 The description ends with a "XD_END" or "XD_SPECIFIER_END" record.
225
226 Some example descriptions :
227
228 static const struct lrecord_description cons_description[] = {
229 { XD_LISP_OBJECT, offsetof (Lisp_Cons, car) },
230 { XD_LISP_OBJECT, offsetof (Lisp_Cons, cdr) },
231 { XD_END }
232 };
233
234 Which means "two lisp objects starting at the 'car' and 'cdr' elements"
235
236 static const struct lrecord_description string_description[] = {
237 { XD_BYTECOUNT, offsetof (Lisp_String, size) },
238 { XD_OPAQUE_DATA_PTR, offsetof (Lisp_String, data), XD_INDIRECT(0, 1) },
239 { XD_LISP_OBJECT, offsetof (Lisp_String, plist) },
240 { XD_END }
241 };
242 "A pointer to string data at 'data', the size of the pointed array being the value
243 of the size variable plus 1, and one lisp object at 'plist'"
244
245 The existing types :
246 XD_LISP_OBJECT
247 A Lisp object. This is also the type to use for pointers to other lrecords.
248
249 XD_LISP_OBJECT_ARRAY
250 An array of Lisp objects or pointers to lrecords.
251 The third element is the count.
252
253 XD_LO_RESET_NIL
254 Lisp objects which will be reset to Qnil when dumping. Useful for cleaning
255 up caches.
256
257 XD_LO_LINK
258 Link in a linked list of objects of the same type.
259
260 XD_OPAQUE_PTR
261 Pointer to undumpable data. Must be NULL when dumping.
262
263 XD_STRUCT_PTR
264 Pointer to described struct. Parameters are number of structures and
265 struct_description.
266
267 XD_OPAQUE_DATA_PTR
268 Pointer to dumpable opaque data. Parameter is the size of the data.
269 Pointed data must be relocatable without changes.
270
271 XD_C_STRING
272 Pointer to a C string.
273
274 XD_DOC_STRING
275 Pointer to a doc string (C string if positive, opaque value if negative)
276
277 XD_INT_RESET
278 An integer which will be reset to a given value in the dump file.
279
280
281 XD_SIZE_T
282 size_t value. Used for counts.
283
284 XD_INT
285 int value. Used for counts.
286
287 XD_LONG
288 long value. Used for counts.
289
290 XD_BYTECOUNT
291 bytecount value. Used for counts.
292
293 XD_END
294 Special type indicating the end of the array.
295
296 XD_SPECIFIER_END
297 Special type indicating the end of the array for a specifier. Extra
298 description is going to be fetched from the specifier methods.
299
300
301 Special macros:
302 XD_INDIRECT(line, delta)
303 Usable where a "count" or "size" is requested. Gives the value of
304 the element which is at line number 'line' in the description (count
305 starts at zero) and adds delta to it.
306 */
307
308 enum lrecord_description_type {
309 XD_LISP_OBJECT_ARRAY,
310 XD_LISP_OBJECT,
311 XD_LO_RESET_NIL,
312 XD_LO_LINK,
313 XD_OPAQUE_PTR,
314 XD_STRUCT_PTR,
315 XD_OPAQUE_DATA_PTR,
316 XD_C_STRING,
317 XD_DOC_STRING,
318 XD_INT_RESET,
319 XD_SIZE_T,
320 XD_INT,
321 XD_LONG,
322 XD_BYTECOUNT,
323 XD_END,
324 XD_SPECIFIER_END
325 };
326
327 struct lrecord_description {
328 enum lrecord_description_type type;
329 int offset;
330 EMACS_INT data1;
331 const struct struct_description *data2;
332 };
333
334 struct struct_description {
335 size_t size;
336 const struct lrecord_description *description;
337 };
338
339 #define XD_INDIRECT(val, delta) (-1-((val)|(delta<<8)))
340
341 #define XD_IS_INDIRECT(code) (code<0)
342 #define XD_INDIRECT_VAL(code) ((-1-code) & 255)
343 #define XD_INDIRECT_DELTA(code) (((-1-code)>>8) & 255)
344
345 #define XD_DYNARR_DESC(base_type, sub_desc) \
346 { XD_STRUCT_PTR, offsetof (base_type, base), XD_INDIRECT(1, 0), sub_desc }, \
347 { XD_INT, offsetof (base_type, cur) }, \
348 { XD_INT_RESET, offsetof (base_type, max), XD_INDIRECT(1, 0) }
254 349
255 /* Declaring the following structures as const puts them in the 350 /* Declaring the following structures as const puts them in the
256 text (read-only) segment, which makes debugging inconvenient 351 text (read-only) segment, which makes debugging inconvenient
257 because this segment is not mapped when processing a core- 352 because this segment is not mapped when processing a core-
258 dump file */ 353 dump file */
259 354
260 #ifdef DEBUG_XEMACS 355 #ifdef DEBUG_XEMACS
261 #define CONST_IF_NOT_DEBUG 356 #define CONST_IF_NOT_DEBUG
262 #else 357 #else
263 #define CONST_IF_NOT_DEBUG CONST 358 #define CONST_IF_NOT_DEBUG const
264 #endif 359 #endif
265 360
266 /* DEFINE_LRECORD_IMPLEMENTATION is for objects with constant size. 361 /* DEFINE_LRECORD_IMPLEMENTATION is for objects with constant size.
267 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION is for objects whose size varies. 362 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION is for objects whose size varies.
268 */ 363 */
271 # define DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) 366 # define DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype)
272 #else 367 #else
273 # define DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) 368 # define DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype)
274 #endif 369 #endif
275 370
276 #define DEFINE_BASIC_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,structtype) \ 371 #define DEFINE_BASIC_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,structtype) \
277 DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,0,0,0,0,structtype) 372 DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,structtype)
278 373
279 #define DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,structtype) \ 374 #define DEFINE_BASIC_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,structtype) \
280 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,sizeof(structtype),0,1,structtype) 375 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,sizeof(structtype),0,1,structtype)
281 376
282 #define DEFINE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,structtype) \ 377 #define DEFINE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,structtype) \
283 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,0,0,0,0,structtype) 378 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,structtype)
284 379
285 #define DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,structtype) \ 380 #define DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,structtype) \
286 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,sizeof (structtype),0,0,structtype) 381 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,sizeof (structtype),0,0,structtype)
287 382
288 #define DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,sizer,structtype) \ 383 #define DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,sizer,structtype) \
289 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,0,0,0,0,sizer,structtype) 384 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,sizer,structtype)
290 385
291 #define DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,sizer,structtype) \ 386 #define DEFINE_BASIC_LRECORD_SEQUENCE_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,sizer,structtype) \
292 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,0,sizer,0,structtype) \ 387 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,0,0,0,0,0,sizer,1,structtype)
293 388
294 #define MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,getprop,putprop,remprop,props,size,sizer,basic_p,structtype) \ 389 #define DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION_WITH_PROPS(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,sizer,structtype) \
390 MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,0,sizer,0,structtype) \
391
392 #define MAKE_LRECORD_IMPLEMENTATION(name,c_name,marker,printer,nuker,equal,hash,desc,getprop,putprop,remprop,plist,size,sizer,basic_p,structtype) \
295 DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) \ 393 DECLARE_ERROR_CHECK_TYPECHECK(c_name, structtype) \
296 static int lrecord_##c_name##_lrecord_type_index; \ 394 static int lrecord_##c_name##_lrecord_type_index; \
297 CONST_IF_NOT_DEBUG struct lrecord_implementation lrecord_##c_name[2] = \ 395 CONST_IF_NOT_DEBUG struct lrecord_implementation lrecord_##c_name = \
298 { { name, marker, printer, nuker, equal, hash, \ 396 { name, marker, printer, nuker, equal, hash, desc, \
299 getprop, putprop, remprop, props, size, sizer, \ 397 getprop, putprop, remprop, plist, size, sizer, \
300 &(lrecord_##c_name##_lrecord_type_index), basic_p }, \ 398 &(lrecord_##c_name##_lrecord_type_index), basic_p } \
301 { 0, 0, 0, this_marks_a_marked_record, 0, 0, 0, 0, 0, 0, 0, 0, 0, basic_p } } 399
302 400 #define LRECORDP(a) (XTYPE (a) == Lisp_Type_Record)
303 #define LRECORDP(a) (XTYPE ((a)) == Lisp_Type_Record)
304 #define XRECORD_LHEADER(a) ((struct lrecord_header *) XPNTR (a)) 401 #define XRECORD_LHEADER(a) ((struct lrecord_header *) XPNTR (a))
305 402
306 #ifdef USE_INDEXED_LRECORD_IMPLEMENTATION 403 #define RECORD_TYPEP(x, ty) \
307 # define RECORD_TYPEP(x, ty) \
308 (LRECORDP (x) && \ 404 (LRECORDP (x) && \
309 lrecord_implementations_table[XRECORD_LHEADER (x)->type] == (ty)) 405 lrecord_implementations_table[XRECORD_LHEADER (x)->type] == (ty))
310 #else
311 # define RECORD_TYPEP(x, ty) \
312 (LRECORDP (x) && XRECORD_LHEADER (x)->implementation == (ty))
313 #endif
314 406
315 /* NOTE: the DECLARE_LRECORD() must come before the associated 407 /* NOTE: the DECLARE_LRECORD() must come before the associated
316 DEFINE_LRECORD_*() or you will get compile errors. 408 DEFINE_LRECORD_*() or you will get compile errors.
317 409
318 Furthermore, you always need to put the DECLARE_LRECORD() in a header 410 Furthermore, you always need to put the DECLARE_LRECORD() in a header
323 415
324 #ifdef ERROR_CHECK_TYPECHECK 416 #ifdef ERROR_CHECK_TYPECHECK
325 417
326 # define DECLARE_LRECORD(c_name, structtype) \ 418 # define DECLARE_LRECORD(c_name, structtype) \
327 extern CONST_IF_NOT_DEBUG struct lrecord_implementation \ 419 extern CONST_IF_NOT_DEBUG struct lrecord_implementation \
328 lrecord_##c_name[]; \ 420 lrecord_##c_name; \
329 INLINE structtype *error_check_##c_name (Lisp_Object obj); \ 421 INLINE structtype *error_check_##c_name (Lisp_Object obj); \
330 INLINE structtype * \ 422 INLINE structtype * \
331 error_check_##c_name (Lisp_Object obj) \ 423 error_check_##c_name (Lisp_Object obj) \
332 { \ 424 { \
333 XUNMARK (obj); \ 425 assert (RECORD_TYPEP (obj, &lrecord_##c_name)); \
334 assert (RECORD_TYPEP (obj, lrecord_##c_name) || \
335 MARKED_RECORD_P (obj)); \
336 return (structtype *) XPNTR (obj); \ 426 return (structtype *) XPNTR (obj); \
337 } \ 427 } \
338 extern Lisp_Object Q##c_name##p 428 extern Lisp_Object Q##c_name##p
339 429
340 # define DECLARE_NONRECORD(c_name, type_enum, structtype) \ 430 # define DECLARE_NONRECORD(c_name, type_enum, structtype) \
341 INLINE structtype *error_check_##c_name (Lisp_Object obj); \ 431 INLINE structtype *error_check_##c_name (Lisp_Object obj); \
342 INLINE structtype * \ 432 INLINE structtype * \
343 error_check_##c_name (Lisp_Object obj) \ 433 error_check_##c_name (Lisp_Object obj) \
344 { \ 434 { \
345 XUNMARK (obj); \ 435 assert (XTYPE (obj) == type_enum); \
346 assert (XGCTYPE (obj) == type_enum); \
347 return (structtype *) XPNTR (obj); \ 436 return (structtype *) XPNTR (obj); \
348 } \ 437 } \
349 extern Lisp_Object Q##c_name##p 438 extern Lisp_Object Q##c_name##p
350 439
351 # define XRECORD(x, c_name, structtype) error_check_##c_name (x) 440 # define XRECORD(x, c_name, structtype) error_check_##c_name (x)
352 # define XNONRECORD(x, c_name, type_enum, structtype) error_check_##c_name (x) 441 # define XNONRECORD(x, c_name, type_enum, structtype) error_check_##c_name (x)
353 442
354 # define XSETRECORD(var, p, c_name) do \ 443 # define XSETRECORD(var, p, c_name) do \
355 { \ 444 { \
356 XSETOBJ (var, Lisp_Type_Record, p); \ 445 XSETOBJ (var, Lisp_Type_Record, p); \
357 assert (RECORD_TYPEP (var, lrecord_##c_name) || \ 446 assert (RECORD_TYPEP (var, &lrecord_##c_name)); \
358 MARKED_RECORD_P (var)); \
359 } while (0) 447 } while (0)
360 448
361 #else /* not ERROR_CHECK_TYPECHECK */ 449 #else /* not ERROR_CHECK_TYPECHECK */
362 450
363 # define DECLARE_LRECORD(c_name, structtype) \ 451 # define DECLARE_LRECORD(c_name, structtype) \
364 extern Lisp_Object Q##c_name##p; \ 452 extern Lisp_Object Q##c_name##p; \
365 extern CONST_IF_NOT_DEBUG struct lrecord_implementation \ 453 extern CONST_IF_NOT_DEBUG struct lrecord_implementation \
366 lrecord_##c_name[] 454 lrecord_##c_name
367 # define DECLARE_NONRECORD(c_name, type_enum, structtype) \ 455 # define DECLARE_NONRECORD(c_name, type_enum, structtype) \
368 extern Lisp_Object Q##c_name##p 456 extern Lisp_Object Q##c_name##p
369 # define XRECORD(x, c_name, structtype) ((structtype *) XPNTR (x)) 457 # define XRECORD(x, c_name, structtype) ((structtype *) XPNTR (x))
370 # define XNONRECORD(x, c_name, type_enum, structtype) \ 458 # define XNONRECORD(x, c_name, type_enum, structtype) \
371 ((structtype *) XPNTR (x)) 459 ((structtype *) XPNTR (x))
372 # define XSETRECORD(var, p, c_name) XSETOBJ (var, Lisp_Type_Record, p) 460 # define XSETRECORD(var, p, c_name) XSETOBJ (var, Lisp_Type_Record, p)
373 461
374 #endif /* not ERROR_CHECK_TYPECHECK */ 462 #endif /* not ERROR_CHECK_TYPECHECK */
375 463
376 #define RECORDP(x, c_name) RECORD_TYPEP (x, lrecord_##c_name) 464 #define RECORDP(x, c_name) RECORD_TYPEP (x, &lrecord_##c_name)
377 #define GC_RECORDP(x, c_name) gc_record_type_p (x, lrecord_##c_name)
378 465
379 /* Note: we now have two different kinds of type-checking macros. 466 /* Note: we now have two different kinds of type-checking macros.
380 The "old" kind has now been renamed CONCHECK_foo. The reason for 467 The "old" kind has now been renamed CONCHECK_foo. The reason for
381 this is that the CONCHECK_foo macros signal a continuable error, 468 this is that the CONCHECK_foo macros signal a continuable error,
382 allowing the user (through debug-on-error) to substitute a different 469 allowing the user (through debug-on-error) to substitute a different
398 485
399 FSF Emacs does not have this problem because RMS took the cheesy 486 FSF Emacs does not have this problem because RMS took the cheesy
400 way out and disabled returning from a signal entirely. */ 487 way out and disabled returning from a signal entirely. */
401 488
402 #define CONCHECK_RECORD(x, c_name) do { \ 489 #define CONCHECK_RECORD(x, c_name) do { \
403 if (!RECORD_TYPEP (x, lrecord_##c_name)) \ 490 if (!RECORD_TYPEP (x, &lrecord_##c_name)) \
404 x = wrong_type_argument (Q##c_name##p, x); \ 491 x = wrong_type_argument (Q##c_name##p, x); \
405 } while (0) 492 } while (0)
406 #define CONCHECK_NONRECORD(x, lisp_enum, predicate) do {\ 493 #define CONCHECK_NONRECORD(x, lisp_enum, predicate) do {\
407 if (XTYPE (x) != lisp_enum) \ 494 if (XTYPE (x) != lisp_enum) \
408 x = wrong_type_argument (predicate, x); \ 495 x = wrong_type_argument (predicate, x); \
409 } while (0) 496 } while (0)
410 #define CHECK_RECORD(x, c_name) do { \ 497 #define CHECK_RECORD(x, c_name) do { \
411 if (!RECORD_TYPEP (x, lrecord_##c_name)) \ 498 if (!RECORD_TYPEP (x, &lrecord_##c_name)) \
412 dead_wrong_type_argument (Q##c_name##p, x); \ 499 dead_wrong_type_argument (Q##c_name##p, x); \
413 } while (0) 500 } while (0)
414 #define CHECK_NONRECORD(x, lisp_enum, predicate) do { \ 501 #define CHECK_NONRECORD(x, lisp_enum, predicate) do { \
415 if (XTYPE (x) != lisp_enum) \ 502 if (XTYPE (x) != lisp_enum) \
416 dead_wrong_type_argument (predicate, x); \ 503 dead_wrong_type_argument (predicate, x); \
417 } while (0) 504 } while (0)
418 505
419 void *alloc_lcrecord (size_t size, CONST struct lrecord_implementation *); 506 void *alloc_lcrecord (size_t size, const struct lrecord_implementation *);
420 507
421 #define alloc_lcrecord_type(type, lrecord_implementation) \ 508 #define alloc_lcrecord_type(type, lrecord_implementation) \
422 ((type *) alloc_lcrecord (sizeof (type), lrecord_implementation)) 509 ((type *) alloc_lcrecord (sizeof (type), lrecord_implementation))
423 510
424 int gc_record_type_p (Lisp_Object frob,
425 CONST struct lrecord_implementation *type);
426
427 /* Copy the data from one lcrecord structure into another, but don't 511 /* Copy the data from one lcrecord structure into another, but don't
428 overwrite the header information. */ 512 overwrite the header information. */
429 513
430 #define copy_lcrecord(dst, src) \ 514 #define copy_lcrecord(dst, src) \
431 memcpy ((char *) dst + sizeof (struct lcrecord_header), \ 515 memcpy ((char *) (dst) + sizeof (struct lcrecord_header), \
432 (char *) src + sizeof (struct lcrecord_header), \ 516 (char *) (src) + sizeof (struct lcrecord_header), \
433 sizeof (*dst) - sizeof (struct lcrecord_header)) 517 sizeof (*(dst)) - sizeof (struct lcrecord_header))
434 518
435 #define zero_lcrecord(lcr) \ 519 #define zero_lcrecord(lcr) \
436 memset ((char *) lcr + sizeof (struct lcrecord_header), 0, \ 520 memset ((char *) (lcr) + sizeof (struct lcrecord_header), 0, \
437 sizeof (*lcr) - sizeof (struct lcrecord_header)) 521 sizeof (*(lcr)) - sizeof (struct lcrecord_header))
438 522
439 #endif /* _XEMACS_LRECORD_H_ */ 523 #endif /* INCLUDED_lrecord_h_ */