Mercurial > hg > xemacs-beta
comparison src/array.h @ 5168:cf900a2f1fa3
extract gap array from extents.c, use in range tables
-------------------- ChangeLog entries follow: --------------------
src/ChangeLog addition:
2010-03-22 Ben Wing <ben@xemacs.org>
* Makefile.in.in (objs):
* array.c:
* array.c (gap_array_adjust_markers):
* array.c (gap_array_move_gap):
* array.c (gap_array_make_gap):
* array.c (gap_array_insert_els):
* array.c (gap_array_delete_els):
* array.c (gap_array_make_marker):
* array.c (gap_array_delete_marker):
* array.c (gap_array_delete_all_markers):
* array.c (gap_array_clone):
* array.h:
* depend:
* emacs.c (main_1):
* extents.c:
* extents.c (EXTENT_GAP_ARRAY_AT):
* extents.c (extent_list_num_els):
* extents.c (extent_list_locate):
* extents.c (extent_list_at):
* extents.c (extent_list_delete_all):
* extents.c (allocate_extent_list):
* extents.c (syms_of_extents):
* extents.h:
* extents.h (XEXTENT_LIST_MARKER):
* lisp.h:
* rangetab.c:
* rangetab.c (mark_range_table):
* rangetab.c (print_range_table):
* rangetab.c (range_table_equal):
* rangetab.c (range_table_hash):
* rangetab.c (verify_range_table):
* rangetab.c (get_range_table_pos):
* rangetab.c (Fmake_range_table):
* rangetab.c (Fcopy_range_table):
* rangetab.c (Fget_range_table):
* rangetab.c (put_range_table):
* rangetab.c (Fclear_range_table):
* rangetab.c (Fmap_range_table):
* rangetab.c (unified_range_table_bytes_needed):
* rangetab.c (unified_range_table_copy_data):
* rangetab.c (unified_range_table_lookup):
* rangetab.h:
* rangetab.h (struct range_table_entry):
* rangetab.h (struct Lisp_Range_Table):
* rangetab.h (rangetab_gap_array_at):
* symsinit.h:
Rename dynarr.c to array.c. Move gap array from extents.c to array.c.
Extract dynarr, gap array and stack-like malloc into new file array.h.
Rename GAP_ARRAY_NUM_ELS -> gap_array_length(). Add gap_array_at(),
gap_array_atp().
Rewrite range table code to use gap arrays. Make put_range_table()
smarter so that its operation is O(log n) for adding a localized
range.
* gc.c (lispdesc_block_size_1):
Don't ABORT() when two elements are located at the same place.
This will happen with a size-0 gap array -- both parts of the array
(before and after gap) are in the same place.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Mon, 22 Mar 2010 19:12:15 -0500 |
parents | |
children | 6c6d78781d59 |
comparison
equal
deleted
inserted
replaced
5167:e374ea766cc1 | 5168:cf900a2f1fa3 |
---|---|
1 /* Header for arrays (dynarrs, gap arrays, etc.). | |
2 Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. | |
3 Copyright (C) 1996, 2001, 2002, 2004, 2005, 2009, 2010 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 /* This file has been Mule-ized, Ben Wing, 10-13-04. */ | |
25 | |
26 #ifndef INCLUDED_array_h_ | |
27 #define INCLUDED_array_h_ | |
28 | |
29 /************************************************************************/ | |
30 /** Definition of dynamic arrays (dynarrs) **/ | |
31 /************************************************************************/ | |
32 | |
33 BEGIN_C_DECLS | |
34 | |
35 /************* Dynarr declaration *************/ | |
36 | |
37 #ifdef NEW_GC | |
38 #define DECLARE_DYNARR_LISP_IMP() \ | |
39 const struct lrecord_implementation *lisp_imp; | |
40 #else | |
41 #define DECLARE_DYNARR_LISP_IMP() | |
42 #endif | |
43 | |
44 #ifdef ERROR_CHECK_DYNARR | |
45 #define DECLARE_DYNARR_LOCKED() \ | |
46 int locked; | |
47 #else | |
48 #define DECLARE_DYNARR_LOCKED() | |
49 #endif | |
50 | |
51 #define Dynarr_declare(type) \ | |
52 struct lrecord_header header; \ | |
53 type *base; \ | |
54 DECLARE_DYNARR_LISP_IMP () \ | |
55 DECLARE_DYNARR_LOCKED () \ | |
56 int elsize_; \ | |
57 int len_; \ | |
58 int largest_; \ | |
59 int max_ | |
60 | |
61 typedef struct dynarr | |
62 { | |
63 Dynarr_declare (void); | |
64 } Dynarr; | |
65 | |
66 #define XD_DYNARR_DESC(base_type, sub_desc) \ | |
67 { XD_BLOCK_PTR, offsetof (base_type, base), \ | |
68 XD_INDIRECT(1, 0), {sub_desc} }, \ | |
69 { XD_INT, offsetof (base_type, len_) }, \ | |
70 { XD_INT_RESET, offsetof (base_type, largest_), XD_INDIRECT(1, 0) }, \ | |
71 { XD_INT_RESET, offsetof (base_type, max_), XD_INDIRECT(1, 0) } | |
72 | |
73 #ifdef NEW_GC | |
74 #define XD_LISP_DYNARR_DESC(base_type, sub_desc) \ | |
75 { XD_LISP_OBJECT_BLOCK_PTR, offsetof (base_type, base), \ | |
76 XD_INDIRECT(1, 0), {sub_desc} }, \ | |
77 { XD_INT, offsetof (base_type, len_) }, \ | |
78 { XD_INT_RESET, offsetof (base_type, largest_), XD_INDIRECT(1, 0) }, \ | |
79 { XD_INT_RESET, offsetof (base_type, max_), XD_INDIRECT(1, 0) } | |
80 #endif /* NEW_GC */ | |
81 | |
82 /************* Dynarr verification *************/ | |
83 | |
84 /* Dynarr locking and verification. | |
85 | |
86 [I] VERIFICATION | |
87 | |
88 Verification routines simply return their basic argument, possibly | |
89 casted, but in the process perform some verification on it, aborting if | |
90 the verification fails. The verification routines take FILE and LINE | |
91 parameters, and use them to output the file and line of the caller | |
92 when an abort occurs, rather than the file and line of the inline | |
93 function, which is less than useful. | |
94 | |
95 There are three basic types of verification routines: | |
96 | |
97 (1) Verify the dynarr itself. This verifies the basic invariant | |
98 involving the length/size values: | |
99 | |
100 0 <= Dynarr_length(d) <= Dynarr_largest(d) <= Dynarr_max(d) | |
101 | |
102 (2) Verify the dynarr itself prior to modifying it. This performs | |
103 the same verification as previously, but also checks that the | |
104 dynarr is not locked (see below). | |
105 | |
106 (3) Verify a dynarr position. Unfortunately we have to have | |
107 different verification routines depending on which kind of operation | |
108 is being performed: | |
109 | |
110 (a) For Dynarr_at(), we check that the POS is bounded by Dynarr_largest(), | |
111 i.e. 0 <= POS < Dynarr_largest(). | |
112 (b) For Dynarr_atp_allow_end(), we also have to allow | |
113 POS == Dynarr_largest(). | |
114 (c) For Dynarr_atp(), we behave largely like Dynarr_at() but make a | |
115 special exception when POS == 0 and Dynarr_largest() == 0 -- see | |
116 comment below. | |
117 (d) Some other routines contain the POS verification within their code, | |
118 and make the check 0 <= POS < Dynarr_length() or | |
119 0 <= POS <= Dynarr_length(). | |
120 | |
121 #### It is not well worked-out whether and in what circumstances it's | |
122 allowed to use a position that is between Dynarr_length() and | |
123 Dynarr_largest(). The ideal solution is to never allow this, and require | |
124 instead that code first change the length before accessing higher | |
125 positions. That would require looking through all the code that accesses | |
126 dynarrs and fixing it appropriately (especially redisplay code, and | |
127 especially redisplay code in the vicinity of a reference to | |
128 Dynarr_largest(), since such code usually checks explicitly to see whether | |
129 there is extra stuff between Dynarr_length() and Dynarr_largest().) | |
130 | |
131 [II] LOCKING | |
132 | |
133 The idea behind dynarr locking is simple: Locking a dynarr prevents | |
134 any modification from occurring, or rather, leads to an abort upon | |
135 any attempt to modify a dynarr. | |
136 | |
137 Dynarr locking was originally added to catch some sporadic and hard-to- | |
138 debug crashes in the redisplay code where dynarrs appeared to be getting | |
139 corrupted in an unexpected fashion. The solution was to lock the | |
140 dynarrs that were getting corrupted (in this case, the display-line | |
141 dynarrs) around calls to routines that weren't supposed to be changing | |
142 these dynarrs but might somehow be calling code that modified them. | |
143 This eventually revealed that there was a reentrancy problem with | |
144 redisplay that involved the QUIT mechanism and the processing done in | |
145 order to determine whether C-g had been pressed -- this processing | |
146 involves retrieving, processing and queueing pending events to see | |
147 whether any of them result in a C-g keypress. However, at least under | |
148 MS Windows this can result in redisplay being called reentrantly. | |
149 For more info:-- | |
150 | |
151 (Info-goto-node "(internals)Critical Redisplay Sections") | |
152 | |
153 */ | |
154 | |
155 #ifdef ERROR_CHECK_DYNARR | |
156 DECLARE_INLINE_HEADER ( | |
157 int | |
158 Dynarr_verify_pos_at (void *d, Elemcount pos, const Ascbyte *file, int line) | |
159 ) | |
160 { | |
161 Dynarr *dy = (Dynarr *) d; | |
162 /* We use `largest', not `len', because the redisplay code often | |
163 accesses stuff between len and largest. */ | |
164 assert_at_line (pos >= 0 && pos < dy->largest_, file, line); | |
165 return pos; | |
166 } | |
167 | |
168 DECLARE_INLINE_HEADER ( | |
169 int | |
170 Dynarr_verify_pos_atp (void *d, Elemcount pos, const Ascbyte *file, int line) | |
171 ) | |
172 { | |
173 Dynarr *dy = (Dynarr *) d; | |
174 /* We use `largest', not `len', because the redisplay code often | |
175 accesses stuff between len and largest. */ | |
176 /* [[ Code will often do something like ... | |
177 | |
178 val = make_bit_vector_from_byte_vector (Dynarr_atp (dyn, 0), | |
179 Dynarr_length (dyn)); | |
180 | |
181 which works fine when the Dynarr_length is non-zero, but when zero, | |
182 the result of Dynarr_atp() not only points past the end of the | |
183 allocated array, but the array may not have ever been allocated and | |
184 hence the return value is NULL. But the length of 0 causes the | |
185 pointer to never get checked. These can occur throughout the code | |
186 so we put in a special check. --ben ]] | |
187 | |
188 Update: The common idiom `Dynarr_atp (dyn, 0)' has been changed to | |
189 `Dynarr_begin (dyn)'. Possibly this special check at POS 0 can be | |
190 done only for Dynarr_begin() not for general Dynarr_atp(). --ben */ | |
191 if (pos == 0 && dy->len_ == 0) | |
192 return pos; | |
193 /* #### It's vaguely possible that some code could legitimately want to | |
194 retrieve a pointer to the position just past the end of dynarr memory. | |
195 This could happen with Dynarr_atp() but not Dynarr_at(). If so, it | |
196 will trigger this assert(). In such cases, it should be obvious that | |
197 the code wants to do this; rather than relaxing the assert, we should | |
198 probably create a new macro Dynarr_atp_allow_end() which is like | |
199 Dynarr_atp() but which allows for pointing at invalid addresses -- we | |
200 really want to check for cases of accessing just past the end of | |
201 memory, which is a likely off-by-one problem to occur and will usually | |
202 not trigger a protection fault (instead, you'll just get random | |
203 behavior, possibly overwriting other memory, which is bad). --ben */ | |
204 assert_at_line (pos >= 0 && pos < dy->largest_, file, line); | |
205 return pos; | |
206 } | |
207 | |
208 DECLARE_INLINE_HEADER ( | |
209 int | |
210 Dynarr_verify_pos_atp_allow_end (void *d, Elemcount pos, const Ascbyte *file, | |
211 int line) | |
212 ) | |
213 { | |
214 Dynarr *dy = (Dynarr *) d; | |
215 /* We use `largest', not `len', because the redisplay code often | |
216 accesses stuff between len and largest. | |
217 We also allow referencing the very end, past the end of allocated | |
218 legitimately space. See comments in Dynarr_verify_pos_atp.()*/ | |
219 assert_at_line (pos >= 0 && pos <= dy->largest_, file, line); | |
220 return pos; | |
221 } | |
222 | |
223 #else | |
224 #define Dynarr_verify_pos_at(d, pos, file, line) (pos) | |
225 #define Dynarr_verify_pos_atp(d, pos, file, line) (pos) | |
226 #define Dynarr_verify_pos_atp_allow_end(d, pos, file, line) (pos) | |
227 #endif /* ERROR_CHECK_DYNARR */ | |
228 | |
229 #ifdef ERROR_CHECK_DYNARR | |
230 DECLARE_INLINE_HEADER ( | |
231 Dynarr * | |
232 Dynarr_verify_1 (void *d, const Ascbyte *file, int line) | |
233 ) | |
234 { | |
235 Dynarr *dy = (Dynarr *) d; | |
236 assert_at_line (dy->len_ >= 0 && dy->len_ <= dy->largest_ && | |
237 dy->largest_ <= dy->max_, file, line); | |
238 return dy; | |
239 } | |
240 | |
241 DECLARE_INLINE_HEADER ( | |
242 Dynarr * | |
243 Dynarr_verify_mod_1 (void *d, const Ascbyte *file, int line) | |
244 ) | |
245 { | |
246 Dynarr *dy = (Dynarr *) d; | |
247 assert_at_line (!dy->locked, file, line); | |
248 return Dynarr_verify_1 (d, file, line); | |
249 } | |
250 | |
251 #define Dynarr_verify(d) Dynarr_verify_1 (d, __FILE__, __LINE__) | |
252 #define Dynarr_verify_mod(d) Dynarr_verify_mod_1 (d, __FILE__, __LINE__) | |
253 | |
254 DECLARE_INLINE_HEADER ( | |
255 void | |
256 Dynarr_lock (void *d) | |
257 ) | |
258 { | |
259 Dynarr *dy = Dynarr_verify_mod (d); | |
260 dy->locked = 1; | |
261 } | |
262 | |
263 DECLARE_INLINE_HEADER ( | |
264 void | |
265 Dynarr_unlock (void *d) | |
266 ) | |
267 { | |
268 Dynarr *dy = Dynarr_verify (d); | |
269 assert (dy->locked); | |
270 dy->locked = 0; | |
271 } | |
272 | |
273 #else /* not ERROR_CHECK_DYNARR */ | |
274 | |
275 #define Dynarr_verify(d) ((Dynarr *) d) | |
276 #define Dynarr_verify_mod(d) ((Dynarr *) d) | |
277 #define Dynarr_lock(d) DO_NOTHING | |
278 #define Dynarr_unlock(d) DO_NOTHING | |
279 | |
280 #endif /* ERROR_CHECK_DYNARR */ | |
281 | |
282 /************* Dynarr creation *************/ | |
283 | |
284 MODULE_API void *Dynarr_newf (Bytecount elsize); | |
285 MODULE_API void Dynarr_free (void *d); | |
286 | |
287 #ifdef NEW_GC | |
288 MODULE_API void *Dynarr_lisp_newf (Bytecount elsize, | |
289 const struct lrecord_implementation | |
290 *dynarr_imp, | |
291 const struct lrecord_implementation *imp); | |
292 | |
293 #define Dynarr_lisp_new(type, dynarr_imp, imp) \ | |
294 ((type##_dynarr *) Dynarr_lisp_newf (sizeof (type), dynarr_imp, imp)) | |
295 #define Dynarr_lisp_new2(dynarr_type, type, dynarr_imp, imp) \ | |
296 ((dynarr_type *) Dynarr_lisp_newf (sizeof (type)), dynarr_imp, imp) | |
297 #endif /* NEW_GC */ | |
298 #define Dynarr_new(type) ((type##_dynarr *) Dynarr_newf (sizeof (type))) | |
299 #define Dynarr_new2(dynarr_type, type) \ | |
300 ((dynarr_type *) Dynarr_newf (sizeof (type))) | |
301 | |
302 /************* Dynarr access *************/ | |
303 | |
304 #ifdef ERROR_CHECK_DYNARR | |
305 #define Dynarr_at(d, pos) \ | |
306 ((d)->base[Dynarr_verify_pos_at (d, pos, __FILE__, __LINE__)]) | |
307 #define Dynarr_atp_allow_end(d, pos) \ | |
308 (&((d)->base[Dynarr_verify_pos_atp_allow_end (d, pos, __FILE__, __LINE__)])) | |
309 #define Dynarr_atp(d, pos) \ | |
310 (&((d)->base[Dynarr_verify_pos_atp (d, pos, __FILE__, __LINE__)])) | |
311 #else | |
312 #define Dynarr_at(d, pos) ((d)->base[pos]) | |
313 #define Dynarr_atp(d, pos) (&Dynarr_at (d, pos)) | |
314 #define Dynarr_atp_allow_end(d, pos) Dynarr_atp (d, pos) | |
315 #endif | |
316 | |
317 /* Old #define Dynarr_atp(d, pos) (&Dynarr_at (d, pos)) */ | |
318 #define Dynarr_begin(d) Dynarr_atp (d, 0) | |
319 #define Dynarr_lastp(d) Dynarr_atp (d, Dynarr_length (d) - 1) | |
320 #define Dynarr_past_lastp(d) Dynarr_atp_allow_end (d, Dynarr_length (d)) | |
321 | |
322 | |
323 /************* Dynarr length/size retrieval and setting *************/ | |
324 | |
325 /* Retrieve the length of a dynarr. The `+ 0' is to ensure that this cannot | |
326 be used as an lvalue. */ | |
327 #define Dynarr_length(d) (Dynarr_verify (d)->len_ + 0) | |
328 /* Retrieve the largest ever length seen of a dynarr. The `+ 0' is to | |
329 ensure that this cannot be used as an lvalue. */ | |
330 #define Dynarr_largest(d) (Dynarr_verify (d)->largest_ + 0) | |
331 /* Retrieve the number of elements that fit in the currently allocated | |
332 space. The `+ 0' is to ensure that this cannot be used as an lvalue. */ | |
333 #define Dynarr_max(d) (Dynarr_verify (d)->max_ + 0) | |
334 /* Return the size in bytes of an element in a dynarr. */ | |
335 #define Dynarr_elsize(d) (Dynarr_verify (d)->elsize_ + 0) | |
336 /* Retrieve the advertised memory usage of a dynarr, i.e. the number of | |
337 bytes occupied by the elements in the dynarr, not counting any overhead. */ | |
338 #define Dynarr_sizeof(d) (Dynarr_length (d) * Dynarr_elsize (d)) | |
339 | |
340 /* Actually set the length of a dynarr. This is a low-level routine that | |
341 should not be directly used; use Dynarr_set_length() or | |
342 Dynarr_set_lengthr() instead. */ | |
343 DECLARE_INLINE_HEADER ( | |
344 void | |
345 Dynarr_set_length_1 (void *d, Elemcount len) | |
346 ) | |
347 { | |
348 Dynarr *dy = Dynarr_verify_mod (d); | |
349 dynarr_checking_assert (len >= 0 && len <= Dynarr_max (dy)); | |
350 /* Use the raw field references here otherwise we get a crash because | |
351 we've set the length but not yet fixed up the largest value. */ | |
352 dy->len_ = len; | |
353 if (dy->len_ > dy->largest_) | |
354 dy->largest_ = dy->len_; | |
355 (void) Dynarr_verify_mod (d); | |
356 } | |
357 | |
358 /* "Restricted set-length": Set the length of dynarr D to LEN, | |
359 which must be in the range [0, Dynarr_largest(d)]. */ | |
360 | |
361 DECLARE_INLINE_HEADER ( | |
362 void | |
363 Dynarr_set_lengthr (void *d, Elemcount len) | |
364 ) | |
365 { | |
366 Dynarr *dy = Dynarr_verify_mod (d); | |
367 dynarr_checking_assert (len >= 0 && len <= Dynarr_largest (dy)); | |
368 Dynarr_set_length_1 (dy, len); | |
369 } | |
370 | |
371 /* "Restricted increment": Increment the length of dynarr D by 1; the resulting | |
372 length must be in the range [0, Dynarr_largest(d)]. */ | |
373 | |
374 #define Dynarr_incrementr(d) Dynarr_set_lengthr (d, Dynarr_length (d) + 1) | |
375 | |
376 | |
377 MODULE_API void Dynarr_resize (void *d, Elemcount size); | |
378 | |
379 DECLARE_INLINE_HEADER ( | |
380 void | |
381 Dynarr_resize_to_fit (void *d, Elemcount size) | |
382 ) | |
383 { | |
384 Dynarr *dy = Dynarr_verify_mod (d); | |
385 if (size > Dynarr_max (dy)) | |
386 Dynarr_resize (dy, size); | |
387 } | |
388 | |
389 #define Dynarr_resize_to_add(d, numels) \ | |
390 Dynarr_resize_to_fit (d, Dynarr_length (d) + numels) | |
391 | |
392 /* This is an optimization. This is like Dynarr_set_length() but the length | |
393 is guaranteed to be at least as big as the existing length. */ | |
394 | |
395 DECLARE_INLINE_HEADER ( | |
396 void | |
397 Dynarr_increase_length (void *d, Elemcount len) | |
398 ) | |
399 { | |
400 Dynarr *dy = Dynarr_verify_mod (d); | |
401 dynarr_checking_assert (len >= Dynarr_length (dy)); | |
402 Dynarr_resize_to_fit (dy, len); | |
403 Dynarr_set_length_1 (dy, len); | |
404 } | |
405 | |
406 /* Set the length of dynarr D to LEN. If the length increases, resize as | |
407 necessary to fit. (NOTE: This will leave uninitialized memory. If you | |
408 aren't planning on immediately overwriting the memory, use | |
409 Dynarr_set_length_and_zero() to zero out all the memory that would | |
410 otherwise be uninitialized.) */ | |
411 | |
412 DECLARE_INLINE_HEADER ( | |
413 void | |
414 Dynarr_set_length (void *d, Elemcount len) | |
415 ) | |
416 { | |
417 Dynarr *dy = Dynarr_verify_mod (d); | |
418 Elemcount old_len = Dynarr_length (dy); | |
419 if (old_len >= len) | |
420 Dynarr_set_lengthr (dy, len); | |
421 else | |
422 Dynarr_increase_length (d, len); | |
423 } | |
424 | |
425 #define Dynarr_increment(d) Dynarr_increase_length (d, Dynarr_length (d) + 1) | |
426 | |
427 /* Zero LEN contiguous elements starting at POS. */ | |
428 | |
429 DECLARE_INLINE_HEADER ( | |
430 void | |
431 Dynarr_zero_many (void *d, Elemcount pos, Elemcount len) | |
432 ) | |
433 { | |
434 Dynarr *dy = Dynarr_verify_mod (d); | |
435 memset ((Rawbyte *) dy->base + pos*Dynarr_elsize (dy), 0, | |
436 len*Dynarr_elsize (dy)); | |
437 } | |
438 | |
439 /* This is an optimization. This is like Dynarr_set_length_and_zero() but | |
440 the length is guaranteed to be at least as big as the existing | |
441 length. */ | |
442 | |
443 DECLARE_INLINE_HEADER ( | |
444 void | |
445 Dynarr_increase_length_and_zero (void *d, Elemcount len) | |
446 ) | |
447 { | |
448 Dynarr *dy = Dynarr_verify_mod (d); | |
449 Elemcount old_len = Dynarr_length (dy); | |
450 Dynarr_increase_length (dy, len); | |
451 Dynarr_zero_many (dy, old_len, len - old_len); | |
452 } | |
453 | |
454 /* Set the length of dynarr D to LEN. If the length increases, resize as | |
455 necessary to fit and zero out all the elements between the old and new | |
456 lengths. */ | |
457 | |
458 DECLARE_INLINE_HEADER ( | |
459 void | |
460 Dynarr_set_length_and_zero (void *d, Elemcount len) | |
461 ) | |
462 { | |
463 Dynarr *dy = Dynarr_verify_mod (d); | |
464 Elemcount old_len = Dynarr_length (dy); | |
465 if (old_len >= len) | |
466 Dynarr_set_lengthr (dy, len); | |
467 else | |
468 Dynarr_increase_length_and_zero (d, len); | |
469 } | |
470 | |
471 /* Reset the dynarr's length to 0. */ | |
472 #define Dynarr_reset(d) Dynarr_set_lengthr (d, 0) | |
473 | |
474 #ifdef MEMORY_USAGE_STATS | |
475 struct usage_stats; | |
476 Bytecount Dynarr_memory_usage (void *d, struct usage_stats *stats); | |
477 #endif | |
478 | |
479 /************* Adding/deleting elements to/from a dynarr *************/ | |
480 | |
481 /* Set the Lisp implementation of the element at POS in dynarr D. Only | |
482 does this if the dynarr holds Lisp objects of a particular type (the | |
483 objects themselves, not pointers to them), and only under NEW_GC. */ | |
484 | |
485 #ifdef NEW_GC | |
486 #define DYNARR_SET_LISP_IMP(d, pos) \ | |
487 do { \ | |
488 if ((d)->lisp_imp) \ | |
489 set_lheader_implementation \ | |
490 ((struct lrecord_header *)&(((d)->base)[pos]), (d)->lisp_imp); \ | |
491 } while (0) | |
492 #else | |
493 #define DYNARR_SET_LISP_IMP(d, pos) DO_NOTHING | |
494 #endif /* (not) NEW_GC */ | |
495 | |
496 /* Add Element EL to the end of dynarr D. */ | |
497 | |
498 #define Dynarr_add(d, el) \ | |
499 do { \ | |
500 Elemcount _da_pos = Dynarr_length (d); \ | |
501 (void) Dynarr_verify_mod (d); \ | |
502 Dynarr_increment (d); \ | |
503 ((d)->base)[_da_pos] = (el); \ | |
504 DYNARR_SET_LISP_IMP (d, _da_pos); \ | |
505 } while (0) | |
506 | |
507 /* Set EL as the element at position POS in dynarr D. | |
508 Expand the dynarr as necessary so that its length is enough to include | |
509 position POS within it, and zero out any new elements created as a | |
510 result of expansion, other than the one at POS. */ | |
511 | |
512 #define Dynarr_set(d, pos, el) \ | |
513 do { \ | |
514 Elemcount _ds_pos = (pos); \ | |
515 (void) Dynarr_verify_mod (d); \ | |
516 if (Dynarr_length (d) < _ds_pos + 1) \ | |
517 Dynarr_increase_length_and_zero (d, _ds_pos + 1); \ | |
518 ((d)->base)[_ds_pos] = (el); \ | |
519 DYNARR_SET_LISP_IMP (d, _ds_pos); \ | |
520 } while (0) | |
521 | |
522 /* Add LEN contiguous elements, stored at BASE, to dynarr D. If BASE is | |
523 NULL, reserve space but don't store anything. */ | |
524 | |
525 DECLARE_INLINE_HEADER ( | |
526 void | |
527 Dynarr_add_many (void *d, const void *base, Elemcount len) | |
528 ) | |
529 { | |
530 /* This duplicates Dynarr_insert_many to some extent; but since it is | |
531 called so often, it seemed useful to remove the unnecessary stuff | |
532 from that function and to make it inline */ | |
533 Dynarr *dy = Dynarr_verify_mod (d); | |
534 Elemcount pos = Dynarr_length (dy); | |
535 Dynarr_increase_length (dy, Dynarr_length (dy) + len); | |
536 if (base) | |
537 memcpy ((Rawbyte *) dy->base + pos*Dynarr_elsize (dy), base, | |
538 len*Dynarr_elsize (dy)); | |
539 } | |
540 | |
541 /* Insert LEN elements, currently pointed to by BASE, into dynarr D | |
542 starting at position POS. */ | |
543 | |
544 MODULE_API void Dynarr_insert_many (void *d, const void *base, Elemcount len, | |
545 Elemcount pos); | |
546 | |
547 /* Prepend LEN elements, currently pointed to by BASE, to the beginning. */ | |
548 | |
549 #define Dynarr_prepend_many(d, base, len) Dynarr_insert_many (d, base, len, 0) | |
550 | |
551 /* Add literal string S to dynarr D, which should hold chars or unsigned | |
552 chars. The final zero byte is not stored. */ | |
553 | |
554 #define Dynarr_add_literal_string(d, s) Dynarr_add_many (d, s, sizeof (s) - 1) | |
555 | |
556 /* Convert Lisp string S to an external encoding according to CODESYS and | |
557 add to dynarr D, which should hold chars or unsigned chars. No final | |
558 zero byte is appended. */ | |
559 | |
560 /* #### This should be an inline function but LISP_STRING_TO_SIZED_EXTERNAL | |
561 isn't declared yet. */ | |
562 | |
563 #define Dynarr_add_ext_lisp_string(d, s, codesys) \ | |
564 do { \ | |
565 Lisp_Object dyna_ls_s = (s); \ | |
566 Lisp_Object dyna_ls_cs = (codesys); \ | |
567 Extbyte *dyna_ls_eb; \ | |
568 Bytecount dyna_ls_bc; \ | |
569 \ | |
570 LISP_STRING_TO_SIZED_EXTERNAL (dyna_ls_s, dyna_ls_eb, \ | |
571 dyna_ls_bc, dyna_ls_cs); \ | |
572 Dynarr_add_many (d, dyna_ls_eb, dyna_ls_bc); \ | |
573 } while (0) | |
574 | |
575 /* Delete LEN elements starting at position POS. */ | |
576 | |
577 MODULE_API void Dynarr_delete_many (void *d, Elemcount pos, Elemcount len); | |
578 | |
579 /* Pop off (i.e. delete) the last element from the dynarr and return it */ | |
580 | |
581 #define Dynarr_pop(d) \ | |
582 (dynarr_checking_assert (Dynarr_length (d) > 0), \ | |
583 Dynarr_verify_mod (d)->len_--, \ | |
584 Dynarr_at (d, Dynarr_length (d))) | |
585 | |
586 /* Delete the item at POS */ | |
587 | |
588 #define Dynarr_delete(d, pos) Dynarr_delete_many (d, pos, 1) | |
589 | |
590 /* Delete the item located at memory address P, which must be a `type *' | |
591 pointer, where `type' is the type of the elements of the dynarr. */ | |
592 #define Dynarr_delete_by_pointer(d, p) \ | |
593 Dynarr_delete_many (d, (p) - ((d)->base), 1) | |
594 | |
595 /* Delete all elements that are numerically equal to EL. */ | |
596 | |
597 #define Dynarr_delete_object(d, el) \ | |
598 do \ | |
599 { \ | |
600 REGISTER int i; \ | |
601 for (i = Dynarr_length (d) - 1; i >= 0; i--) \ | |
602 { \ | |
603 if (el == Dynarr_at (d, i)) \ | |
604 Dynarr_delete_many (d, i, 1); \ | |
605 } \ | |
606 } while (0) | |
607 | |
608 | |
609 /************************************************************************/ | |
610 /** Stack-like malloc/free **/ | |
611 /************************************************************************/ | |
612 | |
613 void *stack_like_malloc (Bytecount size); | |
614 void stack_like_free (void *val); | |
615 | |
616 | |
617 | |
618 /************************************************************************/ | |
619 /** Gap array **/ | |
620 /************************************************************************/ | |
621 | |
622 /* Holds a marker that moves as elements in the array are inserted and | |
623 deleted, similar to standard markers. */ | |
624 | |
625 typedef struct gap_array_marker | |
626 { | |
627 #ifdef NEW_GC | |
628 NORMAL_LISP_OBJECT_HEADER header; | |
629 #endif /* NEW_GC */ | |
630 int pos; | |
631 struct gap_array_marker *next; | |
632 } Gap_Array_Marker; | |
633 | |
634 | |
635 /* Holds a "gap array", which is an array of elements with a gap located | |
636 in it. Insertions and deletions with a high degree of locality | |
637 are very fast, essentially in constant time. Array positions as | |
638 used and returned in the gap array functions are independent of | |
639 the gap. */ | |
640 | |
641 /* Layout of gap array: | |
642 | |
643 <------ gap ------><---- gapsize ----><----- numels - gap ----> | |
644 <---------------------- numels + gapsize ---------------------> | |
645 | |
646 For marking purposes, we use two extra variables computed from | |
647 the others -- the offset to the data past the gap, plus the number | |
648 of elements in that data: | |
649 | |
650 offset_past_gap = elsize * (gap + gapsize) | |
651 els_past_gap = numels - gap | |
652 */ | |
653 | |
654 | |
655 typedef struct gap_array | |
656 { | |
657 #ifdef NEW_GC | |
658 NORMAL_LISP_OBJECT_HEADER header; | |
659 int is_lisp; | |
660 #endif /* NEW_GC */ | |
661 Elemcount gap; | |
662 Elemcount gapsize; | |
663 Elemcount numels; | |
664 Bytecount elsize; | |
665 /* Redundant numbers computed from the others, for marking purposes */ | |
666 Bytecount offset_past_gap; | |
667 Elemcount els_past_gap; | |
668 Gap_Array_Marker *markers; | |
669 /* this is a stretchy array */ | |
670 char array[1]; | |
671 } Gap_Array; | |
672 | |
673 #ifdef NEW_GC | |
674 struct gap_array_marker; | |
675 | |
676 DECLARE_LISP_OBJECT (gap_array_marker, struct gap_array_marker); | |
677 #define XGAP_ARRAY_MARKER(x) \ | |
678 XRECORD (x, gap_array_marker, struct gap_array_marker) | |
679 #define wrap_gap_array_marker(p) wrap_record (p, gap_array_marker) | |
680 #define GAP_ARRAY_MARKERP(x) RECORDP (x, gap_array_marker) | |
681 #define CHECK_GAP_ARRAY_MARKER(x) CHECK_RECORD (x, gap_array_marker) | |
682 #define CONCHECK_GAP_ARRAY_MARKER(x) CONCHECK_RECORD (x, gap_array_marker) | |
683 | |
684 struct gap_array; | |
685 | |
686 DECLARE_LISP_OBJECT (gap_array, struct gap_array); | |
687 #define XGAP_ARRAY(x) XRECORD (x, gap_array, struct gap_array) | |
688 #define wrap_gap_array(p) wrap_record (p, gap_array) | |
689 #define GAP_ARRAYP(x) RECORDP (x, gap_array) | |
690 #define CHECK_GAP_ARRAY(x) CHECK_RECORD (x, gap_array) | |
691 #define CONCHECK_GAP_ARRAY(x) CONCHECK_RECORD (x, gap_array) | |
692 #endif /* NEW_GC */ | |
693 | |
694 #ifdef NEW_GC | |
695 #define XD_GAP_ARRAY_MARKER_DESC \ | |
696 { XD_LISP_OBJECT, offsetof (Gap_Array, markers) } | |
697 #else /* not NEW_GC */ | |
698 #define XD_GAP_ARRAY_MARKER_DESC \ | |
699 { XD_BLOCK_PTR, offsetof (Gap_Array, markers), 1, \ | |
700 { &gap_array_marker_description }, XD_FLAG_NO_KKCC } | |
701 #endif /* not NEW_GC */ | |
702 | |
703 #define XD_GAP_ARRAY_DESC(sub_desc) \ | |
704 { XD_ELEMCOUNT, offsetof (Gap_Array, gap) }, \ | |
705 { XD_BYTECOUNT, offsetof (Gap_Array, offset_past_gap) }, \ | |
706 { XD_ELEMCOUNT, offsetof (Gap_Array, els_past_gap) }, \ | |
707 XD_GAP_ARRAY_MARKER_DESC, \ | |
708 { XD_BLOCK_ARRAY, offsetof (Gap_Array, array), XD_INDIRECT (0, 0), \ | |
709 { sub_desc } }, \ | |
710 { XD_BLOCK_ARRAY, XD_INDIRECT (1, offsetof (Gap_Array, array)), \ | |
711 XD_INDIRECT (2, 0), { sub_desc } } | |
712 | |
713 /* Convert a "memory position" (i.e. taking the gap into account) into | |
714 the address of the element at (i.e. after) that position. "Memory | |
715 positions" are only used internally and are of type Memxpos. | |
716 "Array positions" are used externally and are of type Elemcount. */ | |
717 #define GAP_ARRAY_MEMEL_ADDR(ga, memel) ((ga)->array + (ga)->elsize*(memel)) | |
718 | |
719 /* Number of elements currently in a gap array */ | |
720 #define gap_array_length(ga) ((ga)->numels) | |
721 | |
722 #define gap_array_gappos(ga) ((ga)->gap) | |
723 #define gap_array_gapsize(ga) ((ga)->gapsize) | |
724 | |
725 #define GAP_ARRAY_ARRAY_TO_MEMORY_POS_1(pos, gappos, gapsize) \ | |
726 ((pos) < gappos ? (pos) : (pos) + gapsize) | |
727 | |
728 #define GAP_ARRAY_ARRAY_TO_MEMORY_POS(ga, pos) \ | |
729 GAP_ARRAY_ARRAY_TO_MEMORY_POS_1 (pos, (ga)->gap, (ga)->gapsize) | |
730 | |
731 #define GAP_ARRAY_MEMORY_TO_ARRAY_POS(ga, pos) \ | |
732 ((pos) <= (ga)->gap ? (pos) : (pos) - (ga)->gapsize) | |
733 | |
734 /* Return a pointer to the element at a given position. */ | |
735 #define gap_array_atp(ga, pos, type) \ | |
736 ((type *) GAP_ARRAY_MEMEL_ADDR (ga, GAP_ARRAY_ARRAY_TO_MEMORY_POS (ga, pos))) | |
737 | |
738 /* Return the element at a given position. */ | |
739 #define gap_array_at(ga, pos, type) (*gap_array_atp (ga, pos, type)) | |
740 | |
741 /* Return a pointer to the beginning of memory storage for the gap array. | |
742 Note this is NOT the same as gap_array_atp(ga, 0, type) because that | |
743 will skip forward past the gap if the gap is at position 0. */ | |
744 #define gap_array_begin(ga, type) ((type *) ((ga)->array)) | |
745 | |
746 #ifndef NEW_GC | |
747 extern const struct sized_memory_description lispobj_gap_array_description; | |
748 extern const struct sized_memory_description gap_array_marker_description; | |
749 #endif | |
750 | |
751 Bytecount gap_array_byte_size (Gap_Array *ga); | |
752 Gap_Array *gap_array_insert_els (Gap_Array *ga, Elemcount pos, void *elptr, | |
753 Elemcount numels); | |
754 void gap_array_delete_els (Gap_Array *ga, Elemcount from, Elemcount numdel); | |
755 #define gap_array_delete_all_els(ga) \ | |
756 gap_array_delete_els (ga, 0, gap_array_length (ga)) | |
757 Gap_Array_Marker *gap_array_make_marker (Gap_Array *ga, Elemcount pos); | |
758 void gap_array_delete_marker (Gap_Array *ga, Gap_Array_Marker *m); | |
759 void gap_array_delete_all_markers (Gap_Array *ga); | |
760 void gap_array_move_marker (Gap_Array *ga, Gap_Array_Marker *m, Elemcount pos); | |
761 #define gap_array_marker_pos(ga, m) \ | |
762 GAP_ARRAY_MEMORY_TO_ARRAY_POS (ga, (m)->pos) | |
763 Gap_Array *make_gap_array (Elemcount elsize, int USED_IF_NEW_GC (do_lisp)); | |
764 Gap_Array *gap_array_clone (Gap_Array *ga); | |
765 void free_gap_array (Gap_Array *ga); | |
766 | |
767 #endif /* INCLUDED_lrecordt_h_ */ |