2 * Copyright (c) 2004 Tim J. Robbins.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * "Character map" ADT. Stores mappings between pairs of characters in a
28 * splay tree, with a lookup table cache to simplify looking up the first
29 * bunch of characters (which are presumably more common than others).
39 static struct cmapnode
*cmap_splay(struct cmapnode
*, wint_t);
43 * Allocate a character map.
50 cm
= malloc(sizeof (*cm
));
54 cm
->cm_def
= CM_DEF_SELF
;
55 cm
->cm_havecache
= false;
56 cm
->cm_min
= cm
->cm_max
= 0;
62 * Add a mapping from "from" to "to" to the map.
65 cmap_add(struct cmap
*cm
, wint_t from
, wint_t to
)
67 struct cmapnode
*cmn
, *ncmn
;
69 cm
->cm_havecache
= false;
71 if (cm
->cm_root
== NULL
) {
72 cmn
= malloc(sizeof (*cmn
));
77 cmn
->cmn_left
= cmn
->cmn_right
= NULL
;
79 cm
->cm_min
= cm
->cm_max
= from
;
83 cmn
= cm
->cm_root
= cmap_splay(cm
->cm_root
, from
);
85 if (cmn
->cmn_from
== from
) {
90 ncmn
= malloc(sizeof (*ncmn
));
93 ncmn
->cmn_from
= from
;
95 if (from
< cmn
->cmn_from
) {
96 ncmn
->cmn_left
= cmn
->cmn_left
;
97 ncmn
->cmn_right
= cmn
;
100 ncmn
->cmn_right
= cmn
->cmn_right
;
101 ncmn
->cmn_left
= cmn
;
102 cmn
->cmn_right
= NULL
;
104 if (from
< cm
->cm_min
)
106 if (from
> cm
->cm_max
)
114 * cmap_lookup_hard --
115 * Look up the mapping for a character without using the cache.
118 cmap_lookup_hard(struct cmap
*cm
, wint_t ch
)
121 if (cm
->cm_root
!= NULL
) {
122 cm
->cm_root
= cmap_splay(cm
->cm_root
, ch
);
123 if (cm
->cm_root
->cmn_from
== ch
)
124 return (cm
->cm_root
->cmn_to
);
126 return (cm
->cm_def
== CM_DEF_SELF
? ch
: cm
->cm_def
);
134 cmap_cache(struct cmap
*cm
)
138 for (ch
= 0; ch
< CM_CACHE_SIZE
; ch
++)
139 cm
->cm_cache
[ch
] = cmap_lookup_hard(cm
, ch
);
141 cm
->cm_havecache
= true;
146 * Change the value that characters without mappings map to, and
147 * return the old value. The special character value CM_MAP_SELF
148 * means characters map to themselves.
151 cmap_default(struct cmap
*cm
, wint_t def
)
157 cm
->cm_havecache
= false;
161 static struct cmapnode
*
162 cmap_splay(struct cmapnode
*t
, wint_t ch
)
164 struct cmapnode N
, *l
, *r
, *y
;
167 * Based on public domain code from Sleator.
172 N
.cmn_left
= N
.cmn_right
= NULL
;
175 if (ch
< t
->cmn_from
) {
176 if (t
->cmn_left
!= NULL
&&
177 ch
< t
->cmn_left
->cmn_from
) {
179 t
->cmn_left
= y
->cmn_right
;
183 if (t
->cmn_left
== NULL
)
188 } else if (ch
> t
->cmn_from
) {
189 if (t
->cmn_right
!= NULL
&&
190 ch
> t
->cmn_right
->cmn_from
) {
192 t
->cmn_right
= y
->cmn_left
;
196 if (t
->cmn_right
== NULL
)
204 l
->cmn_right
= t
->cmn_left
;
205 r
->cmn_left
= t
->cmn_right
;
206 t
->cmn_left
= N
.cmn_right
;
207 t
->cmn_right
= N
.cmn_left
;