Mercurial > hg > xemacs-beta
comparison src/rangetab.c @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 859a2309aef8 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 /* XEmacs routines to deal with range tables. | |
2 Copyright (C) 1995 Sun Microsystems, Inc. | |
3 Copyright (C) 1995 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 /* Written by Ben Wing, August 1995. */ | |
25 | |
26 #include <config.h> | |
27 #include "lisp.h" | |
28 | |
29 struct range_table_entry | |
30 { | |
31 EMACS_INT first; | |
32 EMACS_INT last; | |
33 Lisp_Object val; | |
34 }; | |
35 | |
36 typedef struct range_table_entry_dynarr_type | |
37 { | |
38 Dynarr_declare (struct range_table_entry); | |
39 } range_table_entry_dynarr; | |
40 | |
41 struct Lisp_Range_Table | |
42 { | |
43 struct lcrecord_header header; | |
44 range_table_entry_dynarr *entries; | |
45 }; | |
46 | |
47 DECLARE_LRECORD (range_table, struct Lisp_Range_Table); | |
48 #define XRANGE_TABLE(x) \ | |
49 XRECORD (x, range_table, struct Lisp_Range_Table) | |
50 #define XSETRANGE_TABLE(x, p) XSETRECORD (x, p, range_table) | |
51 #define RANGE_TABLEP(x) RECORDP (x, range_table) | |
52 #define GC_RANGE_TABLEP(x) GC_RECORDP (x, range_table) | |
53 #define CHECK_RANGE_TABLE(x) CHECK_RECORD (x, range_table) | |
54 | |
55 Lisp_Object Qrange_tablep; | |
56 Lisp_Object Qrange_table; | |
57 | |
58 | |
59 /************************************************************************/ | |
60 /* Range table object */ | |
61 /************************************************************************/ | |
62 | |
63 /* We use a sorted array of ranges. | |
64 | |
65 #### We should be using the gap array stuff from extents.c. This | |
66 is not hard but just requires moving that stuff out of that file. */ | |
67 | |
68 static Lisp_Object mark_range_table (Lisp_Object, void (*) (Lisp_Object)); | |
69 static void print_range_table (Lisp_Object, Lisp_Object, int); | |
70 static int range_table_equal (Lisp_Object, Lisp_Object, int depth); | |
71 static unsigned long range_table_hash (Lisp_Object obj, int depth); | |
72 DEFINE_LRECORD_IMPLEMENTATION ("range-table", range_table, | |
73 mark_range_table, print_range_table, 0, | |
74 range_table_equal, range_table_hash, | |
75 struct Lisp_Range_Table); | |
76 | |
77 static Lisp_Object | |
78 mark_range_table (Lisp_Object obj, void (*markobj) (Lisp_Object)) | |
79 { | |
80 struct Lisp_Range_Table *rt = XRANGE_TABLE (obj); | |
81 int i; | |
82 | |
83 for (i = 0; i < Dynarr_length (rt->entries); i++) | |
84 (markobj) (Dynarr_at (rt->entries, i).val); | |
85 return Qnil; | |
86 } | |
87 | |
88 static void | |
89 print_range_table (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag) | |
90 { | |
91 struct Lisp_Range_Table *rt = XRANGE_TABLE (obj); | |
92 char buf[200]; | |
93 int i; | |
94 | |
95 write_c_string ("#s(range-table data (", printcharfun); | |
96 for (i = 0; i < Dynarr_length (rt->entries); i++) | |
97 { | |
98 struct range_table_entry *rte = Dynarr_atp (rt->entries, i); | |
99 if (i > 0) | |
100 write_c_string (" ", printcharfun); | |
101 if (rte->first == rte->last) | |
102 sprintf (buf, "%d ", rte->first); | |
103 else | |
104 sprintf (buf, "(%d %d) ", rte->first, rte->last); | |
105 write_c_string (buf, printcharfun); | |
106 print_internal (rte->val, printcharfun, 1); | |
107 } | |
108 write_c_string ("))", printcharfun); | |
109 } | |
110 | |
111 static int | |
112 range_table_equal (Lisp_Object obj1, Lisp_Object obj2, int depth) | |
113 { | |
114 struct Lisp_Range_Table *rt1 = XRANGE_TABLE (obj1); | |
115 struct Lisp_Range_Table *rt2 = XRANGE_TABLE (obj2); | |
116 int i; | |
117 | |
118 if (Dynarr_length (rt1->entries) != Dynarr_length (rt2->entries)) | |
119 return 0; | |
120 | |
121 for (i = 0; i < Dynarr_length (rt1->entries); i++) | |
122 { | |
123 struct range_table_entry *rte1 = Dynarr_atp (rt1->entries, i); | |
124 struct range_table_entry *rte2 = Dynarr_atp (rt2->entries, i); | |
125 | |
126 if (rte1->first != rte2->first | |
127 || rte1->last != rte2->last | |
128 || !internal_equal (rte1->val, rte2->val, depth + 1)) | |
129 return 0; | |
130 } | |
131 | |
132 return 1; | |
133 } | |
134 | |
135 static unsigned long | |
136 range_table_entry_hash (struct range_table_entry *rte, int depth) | |
137 { | |
138 return HASH3 (rte->first, rte->last, internal_hash (rte->val, depth + 1)); | |
139 } | |
140 | |
141 static unsigned long | |
142 range_table_hash (Lisp_Object obj, int depth) | |
143 { | |
144 struct Lisp_Range_Table *rt = XRANGE_TABLE (obj); | |
145 int i; | |
146 int size = Dynarr_length (rt->entries); | |
147 unsigned long hash = size; | |
148 | |
149 /* approach based on internal_array_hash(). */ | |
150 if (size <= 5) | |
151 { | |
152 for (i = 0; i < size; i++) | |
153 hash = HASH2 (hash, | |
154 range_table_entry_hash (Dynarr_atp (rt->entries, i), | |
155 depth)); | |
156 return hash; | |
157 } | |
158 | |
159 /* just pick five elements scattered throughout the array. | |
160 A slightly better approach would be to offset by some | |
161 noise factor from the points chosen below. */ | |
162 for (i = 0; i < 5; i++) | |
163 hash = HASH2 (hash, range_table_entry_hash (Dynarr_atp (rt->entries, | |
164 i*size/5), | |
165 depth)); | |
166 | |
167 return hash; | |
168 } | |
169 | |
170 | |
171 /************************************************************************/ | |
172 /* Range table operations */ | |
173 /************************************************************************/ | |
174 | |
175 #ifdef ERROR_CHECK_TYPECHECK | |
176 | |
177 static void | |
178 verify_range_table (struct Lisp_Range_Table *rt) | |
179 { | |
180 int i; | |
181 | |
182 for (i = 0; i < Dynarr_length (rt->entries); i++) | |
183 { | |
184 struct range_table_entry *rte = Dynarr_atp (rt->entries, i); | |
185 assert (rte->last >= rte->first); | |
186 if (i > 0) | |
187 assert (Dynarr_at (rt->entries, i - 1).last < rte->first); | |
188 } | |
189 } | |
190 | |
191 #else | |
192 | |
193 #define verify_range_table(rt) | |
194 | |
195 #endif | |
196 | |
197 /* Look up in a range table without the Dynarr wrapper. | |
198 Used also by the unified range table format. */ | |
199 | |
200 static Lisp_Object | |
201 get_range_table (EMACS_INT pos, int nentries, struct range_table_entry *tab, | |
202 Lisp_Object defalt) | |
203 { | |
204 int left = 0, right = nentries; | |
205 | |
206 /* binary search for the entry. Based on similar code in | |
207 extent_list_locate(). */ | |
208 while (left != right) | |
209 { | |
210 /* RIGHT might not point to a valid entry (i.e. it's at the end | |
211 of the list), so NEWPOS must round down. */ | |
212 unsigned int newpos = (left + right) >> 1; | |
213 struct range_table_entry *entry = tab + newpos; | |
214 if (pos > entry->last) | |
215 left = newpos+1; | |
216 else if (pos < entry->first) | |
217 right = newpos; | |
218 else | |
219 return entry->val; | |
220 } | |
221 | |
222 return defalt; | |
223 } | |
224 | |
225 DEFUN ("range-table-p", Frange_table_p, Srange_table_p, 1, 1, 0 /* | |
226 Return non-nil if OBJECT is a range table. | |
227 */ ) | |
228 (object) | |
229 Lisp_Object object; | |
230 { | |
231 return (RANGE_TABLEP (object) ? Qt : Qnil); | |
232 } | |
233 | |
234 DEFUN ("make-range-table", Fmake_range_table, Smake_range_table, 0, 0, 0 /* | |
235 Make a new, empty range table. | |
236 You can manipulate it using `put-range-table', `get-range-table', | |
237 `remove-range-table', and `clear-range-table'. | |
238 */ ) | |
239 () | |
240 { | |
241 struct Lisp_Range_Table *rt; | |
242 Lisp_Object obj; | |
243 | |
244 rt = (struct Lisp_Range_Table *) | |
245 alloc_lcrecord (sizeof (struct Lisp_Range_Table), lrecord_range_table); | |
246 rt->entries = Dynarr_new (struct range_table_entry); | |
247 XSETRANGE_TABLE (obj, rt); | |
248 return obj; | |
249 } | |
250 | |
251 DEFUN ("copy-range-table", Fcopy_range_table, Scopy_range_table, 1, 1, 0 /* | |
252 Make a new range table which contains the same values for the same | |
253 ranges as the given table. The values will not themselves be copied. | |
254 */ ) | |
255 (old_table) | |
256 Lisp_Object old_table; | |
257 { | |
258 struct Lisp_Range_Table *rt, *rtnew; | |
259 Lisp_Object obj = Qnil; | |
260 | |
261 CHECK_RANGE_TABLE (old_table); | |
262 rt = XRANGE_TABLE (old_table); | |
263 rtnew = (struct Lisp_Range_Table *) | |
264 alloc_lcrecord (sizeof (struct Lisp_Range_Table), lrecord_range_table); | |
265 rtnew->entries = Dynarr_new (struct range_table_entry); | |
266 | |
267 Dynarr_add_many (rtnew->entries, Dynarr_atp (rt->entries, 0), | |
268 Dynarr_length (rt->entries)); | |
269 XSETRANGE_TABLE (obj, rtnew); | |
270 return obj; | |
271 } | |
272 | |
273 DEFUN ("get-range-table", Fget_range_table, Sget_range_table, 2, 3, 0 /* | |
274 Find value for position POS in TABLE. | |
275 If there is no corresponding value, return DEFAULT (defaults to nil). | |
276 */ ) | |
277 (pos, table, defalt) | |
278 Lisp_Object pos, table, defalt;/* Man kann in C nicht selber buchstabieren */ | |
279 { | |
280 struct Lisp_Range_Table *rt; | |
281 EMACS_INT po; | |
282 | |
283 CHECK_RANGE_TABLE (table); | |
284 rt = XRANGE_TABLE (table); | |
285 | |
286 CHECK_INT_COERCE_CHAR (pos); | |
287 po = XINT (pos); | |
288 | |
289 return get_range_table (po, Dynarr_length (rt->entries), | |
290 Dynarr_atp (rt->entries, 0), defalt); | |
291 } | |
292 | |
293 void | |
294 put_range_table (Lisp_Object table, EMACS_INT first, | |
295 EMACS_INT last, Lisp_Object val) | |
296 { | |
297 int i; | |
298 int insert_me_here = -1; | |
299 struct Lisp_Range_Table *rt = XRANGE_TABLE (table); | |
300 | |
301 /* Now insert in the proper place. This gets tricky because | |
302 we may be overlapping one or more existing ranges and need | |
303 to fix them up. */ | |
304 | |
305 /* First delete all sections of any existing ranges that overlap | |
306 the new range. */ | |
307 for (i = 0; i < Dynarr_length (rt->entries); i++) | |
308 { | |
309 struct range_table_entry *entry = Dynarr_atp (rt->entries, i); | |
310 /* We insert before the first range that begins at or after the | |
311 new range. */ | |
312 if (entry->first >= first && insert_me_here < 0) | |
313 insert_me_here = i; | |
314 if (entry->last < first) | |
315 /* completely before the new range. */ | |
316 continue; | |
317 if (entry->first > last) | |
318 /* completely after the new range. No more possibilities of | |
319 finding overlapping ranges. */ | |
320 break; | |
321 if (entry->first < first && entry->last <= last) | |
322 { | |
323 /* looks like: | |
324 | |
325 [ NEW ] | |
326 [ EXISTING ] | |
327 | |
328 */ | |
329 /* truncate the end off of it. */ | |
330 entry->last = first - 1; | |
331 } | |
332 else if (entry->first < first && entry->last > last) | |
333 /* looks like: | |
334 | |
335 [ NEW ] | |
336 [ EXISTING ] | |
337 | |
338 */ | |
339 /* need to split this one in two. */ | |
340 { | |
341 struct range_table_entry insert_me_too; | |
342 | |
343 insert_me_too.first = last + 1; | |
344 insert_me_too.last = entry->last; | |
345 insert_me_too.val = entry->val; | |
346 entry->last = first - 1; | |
347 Dynarr_insert_many (rt->entries, &insert_me_too, 1, i + 1); | |
348 } | |
349 else if (entry->last > last) | |
350 { | |
351 /* looks like: | |
352 | |
353 [ NEW ] | |
354 [ EXISTING ] | |
355 | |
356 */ | |
357 /* truncate the start off of it. */ | |
358 entry->first = last + 1; | |
359 } | |
360 else | |
361 { | |
362 /* existing is entirely within new. */ | |
363 Dynarr_delete_many (rt->entries, i, 1); | |
364 i--; /* back up since everything shifted one to the left. */ | |
365 } | |
366 } | |
367 | |
368 /* Someone asked us to delete the range, not insert it. */ | |
369 if (UNBOUNDP (val)) | |
370 return; | |
371 | |
372 /* Now insert the new entry, maybe at the end. */ | |
373 | |
374 if (insert_me_here < 0) | |
375 insert_me_here = i; | |
376 | |
377 { | |
378 struct range_table_entry insert_me; | |
379 | |
380 insert_me.first = first; | |
381 insert_me.last = last; | |
382 insert_me.val = val; | |
383 | |
384 Dynarr_insert_many (rt->entries, &insert_me, 1, insert_me_here); | |
385 } | |
386 | |
387 /* Now see if we can combine this entry with adjacent ones just | |
388 before or after. */ | |
389 | |
390 if (insert_me_here > 0) | |
391 { | |
392 struct range_table_entry *entry = Dynarr_atp (rt->entries, | |
393 insert_me_here - 1); | |
394 if (EQ (val, entry->val) && entry->last == first - 1) | |
395 { | |
396 entry->last = last; | |
397 Dynarr_delete_many (rt->entries, insert_me_here, 1); | |
398 insert_me_here--; | |
399 /* We have morphed into a larger range. Update our records | |
400 in case we also combine with the one after. */ | |
401 first = entry->first; | |
402 } | |
403 } | |
404 | |
405 if (insert_me_here < Dynarr_length (rt->entries) - 1) | |
406 { | |
407 struct range_table_entry *entry = Dynarr_atp (rt->entries, | |
408 insert_me_here + 1); | |
409 if (EQ (val, entry->val) && entry->first == last + 1) | |
410 { | |
411 entry->first = first; | |
412 Dynarr_delete_many (rt->entries, insert_me_here, 1); | |
413 } | |
414 } | |
415 } | |
416 | |
417 DEFUN ("put-range-table", Fput_range_table, Sput_range_table, 4, 4, 0 /* | |
418 Set the value for range (START, END) to be VAL in TABLE. | |
419 */ ) | |
420 (start, end, val, table) | |
421 Lisp_Object start, end, val, table; | |
422 { | |
423 EMACS_INT first, last; | |
424 | |
425 CHECK_RANGE_TABLE (table); | |
426 CHECK_INT_COERCE_CHAR (start); | |
427 first = XINT (start); | |
428 CHECK_INT_COERCE_CHAR (end); | |
429 last = XINT (end); | |
430 if (first > last) | |
431 signal_simple_error_2 ("start must be <= end", start, end); | |
432 | |
433 put_range_table (table, first, last, val); | |
434 verify_range_table (XRANGE_TABLE (table)); | |
435 return Qnil; | |
436 } | |
437 | |
438 DEFUN ("remove-range-table", Fremove_range_table, Sremove_range_table, 3, 3, 0 /* | |
439 Remove the value for range (START, END) in TABLE. | |
440 */ ) | |
441 (start, end, table) | |
442 Lisp_Object start, end, table; | |
443 { | |
444 return Fput_range_table (start, end, Qunbound, table); | |
445 } | |
446 | |
447 DEFUN ("clear-range-table", Fclear_range_table, Sclear_range_table, 1, 1, 0 /* | |
448 Flush TABLE. | |
449 */ ) | |
450 (table) | |
451 Lisp_Object table; | |
452 { | |
453 CHECK_RANGE_TABLE (table); | |
454 Dynarr_reset (XRANGE_TABLE (table)->entries); | |
455 return Qnil; | |
456 } | |
457 | |
458 DEFUN ("map-range-table", Fmap_range_table, Smap_range_table, 2, 2, 0 /* | |
459 Map FUNCTION over entries in TABLE, calling it with three args, | |
460 the beginning and end of the range and the corresponding value. | |
461 */ ) | |
462 (function, table) | |
463 Lisp_Object function, table; | |
464 { | |
465 error ("not yet implemented"); | |
466 return Qnil; | |
467 } | |
468 | |
469 | |
470 /************************************************************************/ | |
471 /* Range table read syntax */ | |
472 /************************************************************************/ | |
473 | |
474 static int | |
475 rangetab_data_validate (Lisp_Object keyword, Lisp_Object value, | |
476 Error_behavior errb) | |
477 { | |
478 Lisp_Object rest; | |
479 | |
480 /* #### should deal with errb */ | |
481 EXTERNAL_LIST_LOOP (rest, value) | |
482 { | |
483 Lisp_Object range = XCAR (rest); | |
484 rest = XCDR (rest); | |
485 if (!CONSP (rest)) | |
486 signal_simple_error ("Invalid list format", value); | |
487 if (!INTP (range) && !CHARP (range) | |
488 && !(CONSP (range) && CONSP (XCDR (range)) | |
489 && NILP (XCDR (XCDR (range))) | |
490 && (INTP (XCAR (range)) || CHARP (XCAR (range))) | |
491 && (INTP (XCAR (XCDR (range))) || CHARP (XCAR (XCDR (range)))))) | |
492 signal_simple_error ("Invalid range format", range); | |
493 } | |
494 | |
495 return 1; | |
496 } | |
497 | |
498 static Lisp_Object | |
499 rangetab_instantiate (Lisp_Object data) | |
500 { | |
501 Lisp_Object rangetab = Fmake_range_table (); | |
502 | |
503 if (!NILP (data)) | |
504 { | |
505 data = Fcar (Fcdr (data)); /* skip over 'data keyword */ | |
506 while (!NILP (data)) | |
507 { | |
508 Lisp_Object range = Fcar (data); | |
509 Lisp_Object val = Fcar (Fcdr (data)); | |
510 | |
511 data = Fcdr (Fcdr (data)); | |
512 if (CONSP (range)) | |
513 Fput_range_table (Fcar (range), Fcar (Fcdr (range)), val, | |
514 rangetab); | |
515 else | |
516 Fput_range_table (range, range, val, rangetab); | |
517 } | |
518 } | |
519 | |
520 return rangetab; | |
521 } | |
522 | |
523 | |
524 /************************************************************************/ | |
525 /* Unified range tables */ | |
526 /************************************************************************/ | |
527 | |
528 /* A "unified range table" is a format for storing range tables | |
529 as contiguous blocks of memory. This is used by the regexp | |
530 code, which needs to use range tables to properly handle [] | |
531 constructs in the presence of extended characters but wants to | |
532 store an entire compiled pattern as a contiguous block of memory. | |
533 | |
534 Unified range tables are designed so that they can be placed | |
535 at an arbitrary (possibly mis-aligned) place in memory. | |
536 (Dealing with alignment is a pain in the ass.) | |
537 | |
538 WARNING: No provisions for garbage collection are currently made. | |
539 This means that there must not be any Lisp objects in a unified | |
540 range table that need to be marked for garbage collection. | |
541 Good candidates for objects that can go into a range table are | |
542 | |
543 -- numbers and characters (do not need to be marked) | |
544 -- nil, t (marked elsewhere) | |
545 -- charsets and coding systems (automatically marked because | |
546 they are in a marked list, | |
547 and can't be removed) | |
548 | |
549 Good but slightly less so: | |
550 | |
551 -- symbols (could be uninterned, but that is not likely) | |
552 | |
553 Somewhat less good: | |
554 | |
555 -- buffers, frames, devices (could get deleted) | |
556 | |
557 | |
558 It is expected that you work with range tables in the normal | |
559 format and then convert to unified format when you are done | |
560 making modifications. As such, no functions are provided | |
561 for modifying a unified range table. The only operations | |
562 you can do to unified range tables are | |
563 | |
564 -- look up a value | |
565 -- retrieve all the ranges in an iterative fashion | |
566 | |
567 */ | |
568 | |
569 /* The format of a unified range table is as follows: | |
570 | |
571 -- The first byte contains the number of bytes to skip to find the | |
572 actual start of the table. This deals with alignment constraints, | |
573 since the table might want to go at any arbitrary place in memory. | |
574 -- The next three bytes contain the number of bytes to skip (from the | |
575 *first* byte) to find the stuff after the table. It's stored in | |
576 little-endian format because that's how God intended things. We don't | |
577 necessarily start the stuff at the very end of the table because | |
578 we want to have at least ALIGNOF (EMACS_INT) extra space in case | |
579 we have to move the range table around. (It appears that some | |
580 architectures don't maintain alignment when reallocing.) | |
581 -- At the prescribed offset is a struct unified_range_table, containing | |
582 some number of `struct range_table_entry' entries. */ | |
583 | |
584 struct unified_range_table | |
585 { | |
586 int nentries; | |
587 struct range_table_entry first; | |
588 }; | |
589 | |
590 /* Return size in bytes needed to store the data in a range table. */ | |
591 | |
592 int | |
593 unified_range_table_bytes_needed (Lisp_Object rangetab) | |
594 { | |
595 return (sizeof (struct range_table_entry) * | |
596 (Dynarr_length (XRANGE_TABLE (rangetab)->entries) - 1) + | |
597 sizeof (struct unified_range_table) + | |
598 /* ALIGNOF a struct may be too big. */ | |
599 /* We have four bytes for the size numbers, and an extra | |
600 four or eight bytes for making sure we get the alignment | |
601 OK. */ | |
602 ALIGNOF (EMACS_INT) + 4); | |
603 } | |
604 | |
605 /* Convert a range table into unified format and store in DEST, | |
606 which must be able to hold the number of bytes returned by | |
607 range_table_bytes_needed(). */ | |
608 | |
609 void | |
610 unified_range_table_copy_data (Lisp_Object rangetab, void *dest) | |
611 { | |
612 /* We cast to the above structure rather than just casting to | |
613 char * and adding sizeof(int), because that will lead to | |
614 mis-aligned data on the Alpha machines. */ | |
615 struct unified_range_table *un; | |
616 range_table_entry_dynarr *rted = XRANGE_TABLE (rangetab)->entries; | |
617 int total_needed = unified_range_table_bytes_needed (rangetab); | |
618 void *new_dest = ALIGN_PTR ((char *) dest + 4, ALIGNOF (EMACS_INT)); | |
619 | |
620 * (char *) dest = (char) ((char *) new_dest - (char *) dest); | |
621 * ((unsigned char *) dest + 1) = total_needed & 0xFF; | |
622 total_needed >>= 8; | |
623 * ((unsigned char *) dest + 2) = total_needed & 0xFF; | |
624 total_needed >>= 8; | |
625 * ((unsigned char *) dest + 3) = total_needed & 0xFF; | |
626 un = (struct unified_range_table *) new_dest; | |
627 un->nentries = Dynarr_length (rted); | |
628 memcpy (&un->first, Dynarr_atp (rted, 0), | |
629 sizeof (struct range_table_entry) * Dynarr_length (rted)); | |
630 } | |
631 | |
632 /* Return number of bytes actually used by a unified range table. */ | |
633 | |
634 int | |
635 unified_range_table_bytes_used (void *unrangetab) | |
636 { | |
637 return ((* ((unsigned char *) unrangetab + 1)) | |
638 + ((* ((unsigned char *) unrangetab + 2)) << 8) | |
639 + ((* ((unsigned char *) unrangetab + 3)) << 16)); | |
640 } | |
641 | |
642 /* Make sure the table is aligned, and move it around if it's not. */ | |
643 static void | |
644 align_the_damn_table (void *unrangetab) | |
645 { | |
646 void *cur_dest = (char *) unrangetab + * (char *) unrangetab; | |
647 #if LONGBITS == 64 | |
648 if ((((long) cur_dest) & 7) != 0) | |
649 #else | |
650 if ((((int) cur_dest) & 3) != 0) | |
651 #endif | |
652 { | |
653 int count = (unified_range_table_bytes_used (unrangetab) - 4 | |
654 - ALIGNOF (EMACS_INT)); | |
655 /* Find the proper location, just like above. */ | |
656 void *new_dest = ALIGN_PTR ((char *) unrangetab + 4, | |
657 ALIGNOF (EMACS_INT)); | |
658 /* memmove() works in the presence of overlapping data. */ | |
659 memmove (new_dest, cur_dest, count); | |
660 * (char *) unrangetab = (char) ((char *) new_dest - (char *) unrangetab); | |
661 } | |
662 } | |
663 | |
664 /* Look up a value in a unified range table. */ | |
665 | |
666 Lisp_Object | |
667 unified_range_table_lookup (void *unrangetab, EMACS_INT pos, | |
668 Lisp_Object defalt) | |
669 { | |
670 void *new_dest; | |
671 struct unified_range_table *un; | |
672 | |
673 align_the_damn_table (unrangetab); | |
674 new_dest = (char *) unrangetab + * (char *) unrangetab; | |
675 un = (struct unified_range_table *) new_dest; | |
676 | |
677 return get_range_table (pos, un->nentries, &un->first, defalt); | |
678 } | |
679 | |
680 /* Return number of entries in a unified range table. */ | |
681 | |
682 int | |
683 unified_range_table_nentries (void *unrangetab) | |
684 { | |
685 void *new_dest; | |
686 struct unified_range_table *un; | |
687 | |
688 align_the_damn_table (unrangetab); | |
689 new_dest = (char *) unrangetab + * (char *) unrangetab; | |
690 un = (struct unified_range_table *) new_dest; | |
691 return un->nentries; | |
692 } | |
693 | |
694 /* Return the OFFSETth range (counting from 0) in UNRANGETAB. */ | |
695 void | |
696 unified_range_table_get_range (void *unrangetab, int offset, | |
697 EMACS_INT *min, EMACS_INT *max, | |
698 Lisp_Object *val) | |
699 { | |
700 void *new_dest; | |
701 struct unified_range_table *un; | |
702 struct range_table_entry *tab; | |
703 | |
704 align_the_damn_table (unrangetab); | |
705 new_dest = (char *) unrangetab + * (char *) unrangetab; | |
706 un = (struct unified_range_table *) new_dest; | |
707 | |
708 assert (offset >= 0 && offset < un->nentries); | |
709 tab = (&un->first) + offset; | |
710 *min = tab->first; | |
711 *max = tab->last; | |
712 *val = tab->val; | |
713 } | |
714 | |
715 | |
716 /************************************************************************/ | |
717 /* Initialization */ | |
718 /************************************************************************/ | |
719 | |
720 void | |
721 syms_of_rangetab (void) | |
722 { | |
723 defsymbol (&Qrange_tablep, "range-table-p"); | |
724 defsymbol (&Qrange_table, "range-table"); | |
725 | |
726 defsubr (&Srange_table_p); | |
727 defsubr (&Smake_range_table); | |
728 defsubr (&Scopy_range_table); | |
729 defsubr (&Sget_range_table); | |
730 defsubr (&Sput_range_table); | |
731 defsubr (&Sremove_range_table); | |
732 defsubr (&Sclear_range_table); | |
733 defsubr (&Smap_range_table); | |
734 } | |
735 | |
736 void | |
737 structure_type_create_rangetab (void) | |
738 { | |
739 struct structure_type *st; | |
740 | |
741 st = define_structure_type (Qrange_table, 0, rangetab_instantiate); | |
742 | |
743 define_structure_type_keyword (st, Qdata, rangetab_data_validate); | |
744 } |