ftlru.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /***************************************************************************/
  2. /* */
  3. /* ftlru.c */
  4. /* */
  5. /* Simple LRU list-cache (body). */
  6. /* */
  7. /* Copyright 2000-2001, 2002 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. #include <ft2build.h>
  18. #include FT_CACHE_H
  19. #include FT_CACHE_INTERNAL_LRU_H
  20. #include FT_LIST_H
  21. #include FT_INTERNAL_OBJECTS_H
  22. #include "ftcerror.h"
  23. FT_EXPORT_DEF( FT_Error )
  24. FT_LruList_New( FT_LruList_Class clazz,
  25. FT_UInt max_nodes,
  26. FT_Pointer user_data,
  27. FT_Memory memory,
  28. FT_LruList *alist )
  29. {
  30. FT_Error error;
  31. FT_LruList list;
  32. if ( !alist || !clazz )
  33. return FTC_Err_Invalid_Argument;
  34. *alist = NULL;
  35. if ( !FT_ALLOC( list, clazz->list_size ) )
  36. {
  37. /* initialize common fields */
  38. list->clazz = clazz;
  39. list->memory = memory;
  40. list->max_nodes = max_nodes;
  41. list->data = user_data;
  42. if ( clazz->list_init )
  43. {
  44. error = clazz->list_init( list );
  45. if ( error )
  46. {
  47. if ( clazz->list_done )
  48. clazz->list_done( list );
  49. FT_FREE( list );
  50. }
  51. }
  52. *alist = list;
  53. }
  54. return error;
  55. }
  56. FT_EXPORT_DEF( void )
  57. FT_LruList_Destroy( FT_LruList list )
  58. {
  59. FT_Memory memory;
  60. FT_LruList_Class clazz;
  61. if ( !list )
  62. return;
  63. memory = list->memory;
  64. clazz = list->clazz;
  65. FT_LruList_Reset( list );
  66. if ( clazz->list_done )
  67. clazz->list_done( list );
  68. FT_FREE( list );
  69. }
  70. FT_EXPORT_DEF( void )
  71. FT_LruList_Reset( FT_LruList list )
  72. {
  73. FT_LruNode node;
  74. FT_LruList_Class clazz;
  75. FT_Memory memory;
  76. if ( !list )
  77. return;
  78. node = list->nodes;
  79. clazz = list->clazz;
  80. memory = list->memory;
  81. while ( node )
  82. {
  83. FT_LruNode next = node->next;
  84. if ( clazz->node_done )
  85. clazz->node_done( node, list->data );
  86. FT_FREE( node );
  87. node = next;
  88. }
  89. list->nodes = NULL;
  90. list->num_nodes = 0;
  91. }
  92. FT_EXPORT_DEF( FT_Error )
  93. FT_LruList_Lookup( FT_LruList list,
  94. FT_LruKey key,
  95. FT_LruNode *anode )
  96. {
  97. FT_Error error = 0;
  98. FT_LruNode node, *pnode;
  99. FT_LruList_Class clazz;
  100. FT_LruNode* plast;
  101. FT_LruNode result = NULL;
  102. FT_Memory memory;
  103. if ( !list || !key || !anode )
  104. return FTC_Err_Invalid_Argument;
  105. pnode = &list->nodes;
  106. plast = pnode;
  107. node = NULL;
  108. clazz = list->clazz;
  109. memory = list->memory;
  110. if ( clazz->node_compare )
  111. {
  112. for (;;)
  113. {
  114. node = *pnode;
  115. if ( node == NULL )
  116. break;
  117. if ( clazz->node_compare( node, key, list->data ) )
  118. break;
  119. plast = pnode;
  120. pnode = &(*pnode)->next;
  121. }
  122. }
  123. else
  124. {
  125. for (;;)
  126. {
  127. node = *pnode;
  128. if ( node == NULL )
  129. break;
  130. if ( node->key == key )
  131. break;
  132. plast = pnode;
  133. pnode = &(*pnode)->next;
  134. }
  135. }
  136. if ( node )
  137. {
  138. /* move element to top of list */
  139. if ( list->nodes != node )
  140. {
  141. *pnode = node->next;
  142. node->next = list->nodes;
  143. list->nodes = node;
  144. }
  145. result = node;
  146. goto Exit;
  147. }
  148. /* we haven't found the relevant element. We will now try */
  149. /* to create a new one. */
  150. /* */
  151. /* first, check if our list if full, when appropriate */
  152. if ( list->max_nodes > 0 && list->num_nodes >= list->max_nodes )
  153. {
  154. /* this list list is full; we will now flush */
  155. /* the oldest node, if there's one! */
  156. FT_LruNode last = *plast;
  157. if ( last )
  158. {
  159. if ( clazz->node_flush )
  160. {
  161. error = clazz->node_flush( last, key, list->data );
  162. }
  163. else
  164. {
  165. if ( clazz->node_done )
  166. clazz->node_done( last, list->data );
  167. last->key = key;
  168. error = clazz->node_init( last, key, list->data );
  169. }
  170. if ( !error )
  171. {
  172. /* move it to the top of the list */
  173. *plast = NULL;
  174. last->next = list->nodes;
  175. list->nodes = last;
  176. result = last;
  177. goto Exit;
  178. }
  179. /* in case of error during the flush or done/init cycle, */
  180. /* we need to discard the node */
  181. if ( clazz->node_done )
  182. clazz->node_done( last, list->data );
  183. *plast = NULL;
  184. list->num_nodes--;
  185. FT_FREE( last );
  186. goto Exit;
  187. }
  188. }
  189. /* otherwise, simply allocate a new node */
  190. if ( FT_ALLOC( node, clazz->node_size ) )
  191. goto Exit;
  192. node->key = key;
  193. error = clazz->node_init( node, key, list->data );
  194. if ( error )
  195. {
  196. FT_FREE( node );
  197. goto Exit;
  198. }
  199. result = node;
  200. node->next = list->nodes;
  201. list->nodes = node;
  202. list->num_nodes++;
  203. Exit:
  204. *anode = result;
  205. return error;
  206. }
  207. FT_EXPORT_DEF( void )
  208. FT_LruList_Remove( FT_LruList list,
  209. FT_LruNode node )
  210. {
  211. FT_LruNode *pnode;
  212. if ( !list || !node )
  213. return;
  214. pnode = &list->nodes;
  215. for (;;)
  216. {
  217. if ( *pnode == node )
  218. {
  219. FT_Memory memory = list->memory;
  220. FT_LruList_Class clazz = list->clazz;
  221. *pnode = node->next;
  222. node->next = NULL;
  223. if ( clazz->node_done )
  224. clazz->node_done( node, list->data );
  225. FT_FREE( node );
  226. list->num_nodes--;
  227. break;
  228. }
  229. pnode = &(*pnode)->next;
  230. }
  231. }
  232. FT_EXPORT_DEF( void )
  233. FT_LruList_Remove_Selection( FT_LruList list,
  234. FT_LruNode_SelectFunc select_func,
  235. FT_Pointer select_data )
  236. {
  237. FT_LruNode *pnode, node;
  238. FT_LruList_Class clazz;
  239. FT_Memory memory;
  240. if ( !list || !select_func )
  241. return;
  242. memory = list->memory;
  243. clazz = list->clazz;
  244. pnode = &list->nodes;
  245. for (;;)
  246. {
  247. node = *pnode;
  248. if ( node == NULL )
  249. break;
  250. if ( select_func( node, select_data, list->data ) )
  251. {
  252. *pnode = node->next;
  253. node->next = NULL;
  254. if ( clazz->node_done )
  255. clazz->node_done( node, list );
  256. FT_FREE( node );
  257. }
  258. else
  259. pnode = &(*pnode)->next;
  260. }
  261. }
  262. /* END */