1/****************************************************************************
2 *
3 * ftcmru.c
4 *
5 * FreeType MRU support (body).
6 *
7 * Copyright (C) 2003-2023 by
8 * David Turner, Robert Wilhelm, and Werner Lemberg.
9 *
10 * This file is part of the FreeType project, and may only be used,
11 * modified, and distributed under the terms of the FreeType project
12 * license, LICENSE.TXT. By continuing to use, modify, or distribute
13 * this file you indicate that you have read the license and
14 * understand and accept it fully.
15 *
16 */
17
18
19#include <freetype/ftcache.h>
20#include "ftcmru.h"
21#include <freetype/internal/ftobjs.h>
22#include <freetype/internal/ftdebug.h>
23
24#include "ftcerror.h"
25
26
27 FT_LOCAL_DEF( void )
28 FTC_MruNode_Prepend( FTC_MruNode *plist,
29 FTC_MruNode node )
30 {
31 FTC_MruNode first = *plist;
32
33
34 if ( first )
35 {
36 FTC_MruNode last = first->prev;
37
38
39#ifdef FT_DEBUG_ERROR
40 {
41 FTC_MruNode cnode = first;
42
43
44 do
45 {
46 if ( cnode == node )
47 {
48 fprintf( stderr, "FTC_MruNode_Prepend: invalid action\n" );
49 exit( 2 );
50 }
51 cnode = cnode->next;
52
53 } while ( cnode != first );
54 }
55#endif
56
57 first->prev = node;
58 last->next = node;
59 node->next = first;
60 node->prev = last;
61 }
62 else
63 {
64 node->next = node;
65 node->prev = node;
66 }
67 *plist = node;
68 }
69
70
71 FT_LOCAL_DEF( void )
72 FTC_MruNode_Up( FTC_MruNode *plist,
73 FTC_MruNode node )
74 {
75 FTC_MruNode first = *plist;
76
77
78 FT_ASSERT( first );
79
80 if ( first != node )
81 {
82 FTC_MruNode prev, next, last;
83
84
85#ifdef FT_DEBUG_ERROR
86 {
87 FTC_MruNode cnode = first;
88 do
89 {
90 if ( cnode == node )
91 goto Ok;
92 cnode = cnode->next;
93
94 } while ( cnode != first );
95
96 fprintf( stderr, "FTC_MruNode_Up: invalid action\n" );
97 exit( 2 );
98 Ok:
99 }
100#endif
101 prev = node->prev;
102 next = node->next;
103
104 prev->next = next;
105 next->prev = prev;
106
107 last = first->prev;
108
109 last->next = node;
110 first->prev = node;
111
112 node->next = first;
113 node->prev = last;
114
115 *plist = node;
116 }
117 }
118
119
120 FT_LOCAL_DEF( void )
121 FTC_MruNode_Remove( FTC_MruNode *plist,
122 FTC_MruNode node )
123 {
124 FTC_MruNode first = *plist;
125 FTC_MruNode prev, next;
126
127
128 FT_ASSERT( first );
129
130#ifdef FT_DEBUG_ERROR
131 {
132 FTC_MruNode cnode = first;
133
134
135 do
136 {
137 if ( cnode == node )
138 goto Ok;
139 cnode = cnode->next;
140
141 } while ( cnode != first );
142
143 fprintf( stderr, "FTC_MruNode_Remove: invalid action\n" );
144 exit( 2 );
145 Ok:
146 }
147#endif
148
149 prev = node->prev;
150 next = node->next;
151
152 prev->next = next;
153 next->prev = prev;
154
155 if ( node == next )
156 {
157 FT_ASSERT( first == node );
158 FT_ASSERT( prev == node );
159
160 *plist = NULL;
161 }
162 else if ( node == first )
163 *plist = next;
164 }
165
166
167 FT_LOCAL_DEF( void )
168 FTC_MruList_Init( FTC_MruList list,
169 FTC_MruListClass clazz,
170 FT_UInt max_nodes,
171 FT_Pointer data,
172 FT_Memory memory )
173 {
174 list->num_nodes = 0;
175 list->max_nodes = max_nodes;
176 list->nodes = NULL;
177 list->clazz = *clazz;
178 list->data = data;
179 list->memory = memory;
180 }
181
182
183 FT_LOCAL_DEF( void )
184 FTC_MruList_Reset( FTC_MruList list )
185 {
186 while ( list->nodes )
187 FTC_MruList_Remove( list, list->nodes );
188
189 FT_ASSERT( list->num_nodes == 0 );
190 }
191
192
193 FT_LOCAL_DEF( void )
194 FTC_MruList_Done( FTC_MruList list )
195 {
196 FTC_MruList_Reset( list );
197 }
198
199
200#ifndef FTC_INLINE
201 FT_LOCAL_DEF( FTC_MruNode )
202 FTC_MruList_Find( FTC_MruList list,
203 FT_Pointer key )
204 {
205 FTC_MruNode_CompareFunc compare = list->clazz.node_compare;
206 FTC_MruNode first, node;
207
208
209 first = list->nodes;
210 node = NULL;
211
212 if ( first )
213 {
214 node = first;
215 do
216 {
217 if ( compare( node, key ) )
218 {
219 if ( node != first )
220 FTC_MruNode_Up( &list->nodes, node );
221
222 return node;
223 }
224
225 node = node->next;
226
227 } while ( node != first);
228 }
229
230 return NULL;
231 }
232#endif
233
234 FT_LOCAL_DEF( FT_Error )
235 FTC_MruList_New( FTC_MruList list,
236 FT_Pointer key,
237 FTC_MruNode *anode )
238 {
239 FT_Error error;
240 FTC_MruNode node = NULL;
241 FT_Memory memory = list->memory;
242
243
244 if ( list->num_nodes >= list->max_nodes && list->max_nodes > 0 )
245 {
246 node = list->nodes->prev;
247
248 FT_ASSERT( node );
249
250 if ( list->clazz.node_reset )
251 {
252 FTC_MruNode_Up( &list->nodes, node );
253
254 error = list->clazz.node_reset( node, key, list->data );
255 if ( !error )
256 goto Exit;
257 }
258
259 FTC_MruNode_Remove( &list->nodes, node );
260 list->num_nodes--;
261
262 if ( list->clazz.node_done )
263 list->clazz.node_done( node, list->data );
264 }
265
266 /* zero new node in case of node_init failure */
267 else if ( FT_ALLOC( node, list->clazz.node_size ) )
268 goto Exit;
269
270 error = list->clazz.node_init( node, key, list->data );
271 if ( error )
272 goto Fail;
273
274 FTC_MruNode_Prepend( &list->nodes, node );
275 list->num_nodes++;
276
277 Exit:
278 *anode = node;
279 return error;
280
281 Fail:
282 if ( list->clazz.node_done )
283 list->clazz.node_done( node, list->data );
284
285 FT_FREE( node );
286 goto Exit;
287 }
288
289
290#ifndef FTC_INLINE
291 FT_LOCAL_DEF( FT_Error )
292 FTC_MruList_Lookup( FTC_MruList list,
293 FT_Pointer key,
294 FTC_MruNode *anode )
295 {
296 FTC_MruNode node;
297
298
299 node = FTC_MruList_Find( list, key );
300 if ( !node )
301 return FTC_MruList_New( list, key, anode );
302
303 *anode = node;
304 return 0;
305 }
306#endif /* FTC_INLINE */
307
308 FT_LOCAL_DEF( void )
309 FTC_MruList_Remove( FTC_MruList list,
310 FTC_MruNode node )
311 {
312 FTC_MruNode_Remove( &list->nodes, node );
313 list->num_nodes--;
314
315 {
316 FT_Memory memory = list->memory;
317
318
319 if ( list->clazz.node_done )
320 list->clazz.node_done( node, list->data );
321
322 FT_FREE( node );
323 }
324 }
325
326
327 FT_LOCAL_DEF( void )
328 FTC_MruList_RemoveSelection( FTC_MruList list,
329 FTC_MruNode_CompareFunc selection,
330 FT_Pointer key )
331 {
332 FTC_MruNode first = list->nodes;
333 FTC_MruNode prev, node;
334
335
336 if ( !first || !selection )
337 return;
338
339 prev = first->prev;
340 do
341 {
342 node = prev;
343 prev = node->prev;
344
345 if ( selection( node, key ) )
346 FTC_MruList_Remove( list, node );
347
348 } while ( node != first );
349 }
350
351
352/* END */
353