comparison src/array.h @ 5495:1f0b15040456

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