2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2004 Tim J. Robbins.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * "Character map" ADT. Stores mappings between pairs of characters in a
30 * splay tree, with a lookup table cache to simplify looking up the first
31 * bunch of characters (which are presumably more common than others).
34 #include <sys/cdefs.h>
42 static struct cmapnode
*cmap_splay(struct cmapnode
*, wint_t);
46 * Allocate a character map.
53 cm
= malloc(sizeof(*cm
));
57 cm
->cm_def
= CM_DEF_SELF
;
58 cm
->cm_havecache
= false;
59 cm
->cm_min
= cm
->cm_max
= 0;
65 * Add a mapping from "from" to "to" to the map.
68 cmap_add(struct cmap
*cm
, wint_t from
, wint_t to
)
70 struct cmapnode
*cmn
, *ncmn
;
72 cm
->cm_havecache
= false;
74 if (cm
->cm_root
== NULL
) {
75 cmn
= malloc(sizeof(*cmn
));
80 cmn
->cmn_left
= cmn
->cmn_right
= NULL
;
82 cm
->cm_min
= cm
->cm_max
= from
;
86 cmn
= cm
->cm_root
= cmap_splay(cm
->cm_root
, from
);
88 if (cmn
->cmn_from
== from
) {
93 ncmn
= malloc(sizeof(*ncmn
));
96 ncmn
->cmn_from
= from
;
98 if (from
< cmn
->cmn_from
) {
99 ncmn
->cmn_left
= cmn
->cmn_left
;
100 ncmn
->cmn_right
= cmn
;
101 cmn
->cmn_left
= NULL
;
103 ncmn
->cmn_right
= cmn
->cmn_right
;
104 ncmn
->cmn_left
= cmn
;
105 cmn
->cmn_right
= NULL
;
107 if (from
< cm
->cm_min
)
109 if (from
> cm
->cm_max
)
117 * cmap_lookup_hard --
118 * Look up the mapping for a character without using the cache.
121 cmap_lookup_hard(struct cmap
*cm
, wint_t ch
)
124 if (cm
->cm_root
!= NULL
) {
125 cm
->cm_root
= cmap_splay(cm
->cm_root
, ch
);
126 if (cm
->cm_root
->cmn_from
== ch
)
127 return (cm
->cm_root
->cmn_to
);
129 return (cm
->cm_def
== CM_DEF_SELF
? ch
: cm
->cm_def
);
137 cmap_cache(struct cmap
*cm
)
141 for (ch
= 0; ch
< CM_CACHE_SIZE
; ch
++)
142 cm
->cm_cache
[ch
] = cmap_lookup_hard(cm
, ch
);
144 cm
->cm_havecache
= true;
149 * Change the value that characters without mappings map to, and
150 * return the old value. The special character value CM_MAP_SELF
151 * means characters map to themselves.
154 cmap_default(struct cmap
*cm
, wint_t def
)
160 cm
->cm_havecache
= false;
164 static struct cmapnode
*
165 cmap_splay(struct cmapnode
*t
, wint_t ch
)
167 struct cmapnode N
, *l
, *r
, *y
;
170 * Based on public domain code from Sleator.
175 N
.cmn_left
= N
.cmn_right
= NULL
;
178 if (ch
< t
->cmn_from
) {
179 if (t
->cmn_left
!= NULL
&&
180 ch
< t
->cmn_left
->cmn_from
) {
182 t
->cmn_left
= y
->cmn_right
;
186 if (t
->cmn_left
== NULL
)
191 } else if (ch
> t
->cmn_from
) {
192 if (t
->cmn_right
!= NULL
&&
193 ch
> t
->cmn_right
->cmn_from
) {
195 t
->cmn_right
= y
->cmn_left
;
199 if (t
->cmn_right
== NULL
)
207 l
->cmn_right
= t
->cmn_left
;
208 r
->cmn_left
= t
->cmn_right
;
209 t
->cmn_left
= N
.cmn_right
;
210 t
->cmn_right
= N
.cmn_left
;