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 }