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