1 /* Copyright (C) 2000-2001, 2003 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Bruno Haible <haible@clisp.cons.org>, 2000.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 /* Construction of sparse 3-level tables.
21 See wchar-lookup.h or coll-lookup.h for their structure and the
24 Before including this file, set
25 TABLE to the name of the structure to be defined
26 ELEMENT to the type of every entry
27 DEFAULT to the default value for empty entries
28 ITERATE if you want the TABLE_iterate function to be defined
29 NO_FINALIZE if you don't want the TABLE_finalize function to be defined
34 void TABLE_init (struct TABLE *t);
35 ELEMENT TABLE_get (struct TABLE *t, uint32_t wc);
36 void TABLE_add (struct TABLE *t, uint32_t wc, ELEMENT value);
37 void TABLE_iterate (struct TABLE *t,
38 void (*fn) (uint32_t wc, ELEMENT value));
39 void TABLE_finalize (struct TABLE *t);
42 #define CONCAT(a,b) CONCAT1(a,b)
43 #define CONCAT1(a,b) a##b
50 /* Working representation. */
60 /* Compressed representation. */
65 /* Initialize. Assumes t->p and t->q have already been set. */
67 CONCAT(TABLE
,_init
) (struct TABLE
*t
)
70 t
->level1_alloc
= t
->level1_size
= 0;
72 t
->level2_alloc
= t
->level2_size
= 0;
74 t
->level3_alloc
= t
->level3_size
= 0;
77 /* Marker for an empty slot. This has the value 0xFFFFFFFF, regardless
78 whether 'int' is 16 bit, 32 bit, or 64 bit. */
79 #define EMPTY ((uint32_t) ~0)
81 /* Retrieve an entry. */
83 __attribute ((always_inline
))
84 CONCAT(TABLE
,_get
) (struct TABLE
*t
, uint32_t wc
)
86 uint32_t index1
= wc
>> (t
->q
+ t
->p
);
87 if (index1
< t
->level1_size
)
89 uint32_t lookup1
= t
->level1
[index1
];
92 uint32_t index2
= ((wc
>> t
->p
) & ((1 << t
->q
) - 1))
94 uint32_t lookup2
= t
->level2
[index2
];
97 uint32_t index3
= (wc
& ((1 << t
->p
) - 1))
99 ELEMENT lookup3
= t
->level3
[index3
];
110 CONCAT(TABLE
,_add
) (struct TABLE
*t
, uint32_t wc
, ELEMENT value
)
112 uint32_t index1
= wc
>> (t
->q
+ t
->p
);
113 uint32_t index2
= (wc
>> t
->p
) & ((1 << t
->q
) - 1);
114 uint32_t index3
= wc
& ((1 << t
->p
) - 1);
117 if (value
== CONCAT(TABLE
,_get
) (t
, wc
))
120 if (index1
>= t
->level1_size
)
122 if (index1
>= t
->level1_alloc
)
124 size_t alloc
= 2 * t
->level1_alloc
;
127 t
->level1
= (uint32_t *) xrealloc ((char *) t
->level1
,
128 alloc
* sizeof (uint32_t));
129 t
->level1_alloc
= alloc
;
131 while (index1
>= t
->level1_size
)
132 t
->level1
[t
->level1_size
++] = EMPTY
;
135 if (t
->level1
[index1
] == EMPTY
)
137 if (t
->level2_size
== t
->level2_alloc
)
139 size_t alloc
= 2 * t
->level2_alloc
+ 1;
140 t
->level2
= (uint32_t *) xrealloc ((char *) t
->level2
,
141 (alloc
<< t
->q
) * sizeof (uint32_t));
142 t
->level2_alloc
= alloc
;
144 i1
= t
->level2_size
<< t
->q
;
145 i2
= (t
->level2_size
+ 1) << t
->q
;
146 for (i
= i1
; i
< i2
; i
++)
147 t
->level2
[i
] = EMPTY
;
148 t
->level1
[index1
] = t
->level2_size
++;
151 index2
+= t
->level1
[index1
] << t
->q
;
153 if (t
->level2
[index2
] == EMPTY
)
155 if (t
->level3_size
== t
->level3_alloc
)
157 size_t alloc
= 2 * t
->level3_alloc
+ 1;
158 t
->level3
= (ELEMENT
*) xrealloc ((char *) t
->level3
,
159 (alloc
<< t
->p
) * sizeof (ELEMENT
));
160 t
->level3_alloc
= alloc
;
162 i1
= t
->level3_size
<< t
->p
;
163 i2
= (t
->level3_size
+ 1) << t
->p
;
164 for (i
= i1
; i
< i2
; i
++)
165 t
->level3
[i
] = DEFAULT
;
166 t
->level2
[index2
] = t
->level3_size
++;
169 index3
+= t
->level2
[index2
] << t
->p
;
171 t
->level3
[index3
] = value
;
175 /* Apply a function to all entries in the table. */
177 CONCAT(TABLE
,_iterate
) (struct TABLE
*t
,
178 void (*fn
) (uint32_t wc
, ELEMENT value
))
181 for (index1
= 0; index1
< t
->level1_size
; index1
++)
183 uint32_t lookup1
= t
->level1
[index1
];
184 if (lookup1
!= EMPTY
)
186 uint32_t lookup1_shifted
= lookup1
<< t
->q
;
188 for (index2
= 0; index2
< (1 << t
->q
); index2
++)
190 uint32_t lookup2
= t
->level2
[index2
+ lookup1_shifted
];
191 if (lookup2
!= EMPTY
)
193 uint32_t lookup2_shifted
= lookup2
<< t
->p
;
195 for (index3
= 0; index3
< (1 << t
->p
); index3
++)
197 ELEMENT lookup3
= t
->level3
[index3
+ lookup2_shifted
];
198 if (lookup3
!= DEFAULT
)
199 fn ((((index1
<< t
->q
) + index2
) << t
->p
) + index3
,
208 /* GCC ATM seems to do a poor job with pointers to nested functions passed
209 to inlined functions. Help it a little bit with this hack. */
210 #define wchead_table_iterate(tp, fn) \
213 struct wchead_table *t = (tp); \
215 for (index1 = 0; index1 < t->level1_size; index1++) \
217 uint32_t lookup1 = t->level1[index1]; \
218 if (lookup1 != ((uint32_t) ~0)) \
220 uint32_t lookup1_shifted = lookup1 << t->q; \
222 for (index2 = 0; index2 < (1 << t->q); index2++) \
224 uint32_t lookup2 = t->level2[index2 + lookup1_shifted]; \
225 if (lookup2 != ((uint32_t) ~0)) \
227 uint32_t lookup2_shifted = lookup2 << t->p; \
229 for (index3 = 0; index3 < (1 << t->p); index3++) \
231 struct element_t *lookup3 \
232 = t->level3[index3 + lookup2_shifted]; \
233 if (lookup3 != NULL) \
234 fn ((((index1 << t->q) + index2) << t->p) + index3, \
246 /* Finalize and shrink. */
248 CONCAT(TABLE
,_finalize
) (struct TABLE
*t
)
251 uint32_t reorder3
[t
->level3_size
];
252 uint32_t reorder2
[t
->level2_size
];
253 uint32_t level1_offset
, level2_offset
, level3_offset
, last_offset
;
255 /* Uniquify level3 blocks. */
257 for (j
= 0; j
< t
->level3_size
; j
++)
259 for (i
= 0; i
< k
; i
++)
260 if (memcmp (&t
->level3
[i
<< t
->p
], &t
->level3
[j
<< t
->p
],
261 (1 << t
->p
) * sizeof (ELEMENT
)) == 0)
263 /* Relocate block j to block i. */
268 memcpy (&t
->level3
[i
<< t
->p
], &t
->level3
[j
<< t
->p
],
269 (1 << t
->p
) * sizeof (ELEMENT
));
275 for (i
= 0; i
< (t
->level2_size
<< t
->q
); i
++)
276 if (t
->level2
[i
] != EMPTY
)
277 t
->level2
[i
] = reorder3
[t
->level2
[i
]];
279 /* Uniquify level2 blocks. */
281 for (j
= 0; j
< t
->level2_size
; j
++)
283 for (i
= 0; i
< k
; i
++)
284 if (memcmp (&t
->level2
[i
<< t
->q
], &t
->level2
[j
<< t
->q
],
285 (1 << t
->q
) * sizeof (uint32_t)) == 0)
287 /* Relocate block j to block i. */
292 memcpy (&t
->level2
[i
<< t
->q
], &t
->level2
[j
<< t
->q
],
293 (1 << t
->q
) * sizeof (uint32_t));
299 for (i
= 0; i
< t
->level1_size
; i
++)
300 if (t
->level1
[i
] != EMPTY
)
301 t
->level1
[i
] = reorder2
[t
->level1
[i
]];
303 /* Create and fill the resulting compressed representation. */
305 5 * sizeof (uint32_t)
306 + t
->level1_size
* sizeof (uint32_t)
307 + (t
->level2_size
<< t
->q
) * sizeof (uint32_t)
308 + (t
->level3_size
<< t
->p
) * sizeof (ELEMENT
);
309 t
->result_size
= (last_offset
+ 3) & ~3ul;
310 t
->result
= (char *) xmalloc (t
->result_size
);
313 5 * sizeof (uint32_t);
315 5 * sizeof (uint32_t)
316 + t
->level1_size
* sizeof (uint32_t);
318 5 * sizeof (uint32_t)
319 + t
->level1_size
* sizeof (uint32_t)
320 + (t
->level2_size
<< t
->q
) * sizeof (uint32_t);
322 ((uint32_t *) t
->result
)[0] = t
->q
+ t
->p
;
323 ((uint32_t *) t
->result
)[1] = t
->level1_size
;
324 ((uint32_t *) t
->result
)[2] = t
->p
;
325 ((uint32_t *) t
->result
)[3] = (1 << t
->q
) - 1;
326 ((uint32_t *) t
->result
)[4] = (1 << t
->p
) - 1;
328 for (i
= 0; i
< t
->level1_size
; i
++)
329 ((uint32_t *) (t
->result
+ level1_offset
))[i
] =
330 (t
->level1
[i
] == EMPTY
332 : (t
->level1
[i
] << t
->q
) * sizeof (uint32_t) + level2_offset
);
334 for (i
= 0; i
< (t
->level2_size
<< t
->q
); i
++)
335 ((uint32_t *) (t
->result
+ level2_offset
))[i
] =
336 (t
->level2
[i
] == EMPTY
338 : (t
->level2
[i
] << t
->p
) * sizeof (ELEMENT
) + level3_offset
);
340 for (i
= 0; i
< (t
->level3_size
<< t
->p
); i
++)
341 ((ELEMENT
*) (t
->result
+ level3_offset
))[i
] = t
->level3
[i
];
343 if (last_offset
< t
->result_size
)
344 memset (t
->result
+ last_offset
, 0, t
->result_size
- last_offset
);
346 if (t
->level1_alloc
> 0)
348 if (t
->level2_alloc
> 0)
350 if (t
->level3_alloc
> 0)