image_container.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. #include <rtgui/image_container.h>
  2. #ifdef RTGUI_IMAGE_CONTAINER
  3. typedef unsigned int (*rtgui_hash_func_t)(const void *key);
  4. typedef struct _rtgui_hash_table rtgui_hash_table_t;
  5. typedef rt_bool_t (*rtgui_equal_func_t)(const void *a, const void *b);
  6. typedef void (*rtgui_user_func_t)(const void *value, const void *data);
  7. /*
  8. *Hash tables
  9. */
  10. rtgui_hash_table_t *hash_table_create(rtgui_hash_func_t hash_func, rtgui_equal_func_t key_equal_func);
  11. void hash_table_destroy(rtgui_hash_table_t *hash_table);
  12. void *hash_table_find(rtgui_hash_table_t *hash_table, const void *key);
  13. void hash_table_insert(rtgui_hash_table_t *hash_table, const void *key, void *value);
  14. rt_bool_t hash_table_remove(rtgui_hash_table_t *hash_table, const void *key);
  15. void hash_table_foreach(rtgui_hash_table_t *hash_table, rtgui_user_func_t user_func, void *data);
  16. unsigned int hash_table_get_size(rtgui_hash_table_t *hash_table);
  17. /* Hash Functions
  18. */
  19. unsigned int direct_hash(const void *v);
  20. #define HASH_TABLE_MIN_SIZE 11
  21. #define HASH_TABLE_MAX_SIZE 6247
  22. typedef struct _gui_hash_node rtgui_hash_node_t;
  23. struct _gui_hash_node
  24. {
  25. void *key;
  26. void *value;
  27. rtgui_hash_node_t *next;
  28. };
  29. struct _rtgui_hash_table
  30. {
  31. rt_uint16_t size;
  32. rt_uint16_t nnodes;
  33. rtgui_hash_node_t **nodes;
  34. rtgui_hash_func_t hash_func;
  35. rtgui_equal_func_t key_equal_func;
  36. };
  37. static const unsigned int primes[] =
  38. {
  39. 11,
  40. 19,
  41. 37,
  42. 73,
  43. 109,
  44. 163,
  45. 251,
  46. 367,
  47. 557,
  48. 823,
  49. 1237,
  50. 1861,
  51. 2777,
  52. 4177,
  53. 6247,
  54. /*
  55. 9371,
  56. 14057,
  57. 21089,
  58. 31627,
  59. 47431,
  60. 71143,
  61. 106721,
  62. 160073,
  63. 240101,
  64. 360163,
  65. 540217,
  66. 810343,
  67. 1215497,
  68. 1823231,
  69. 2734867,
  70. 4102283,
  71. 6153409,
  72. 9230113,
  73. 13845163,
  74. */
  75. };
  76. static const unsigned int nprimes = sizeof(primes) / sizeof(primes[0]);
  77. static void hash_table_resize(rtgui_hash_table_t *hash_table);
  78. static rtgui_hash_node_t **hash_table_find_node(rtgui_hash_table_t *hash_table, const void *key);
  79. static rtgui_hash_node_t *hash_node_create(const void *key, void *value);
  80. static void hash_node_destroy(rtgui_hash_node_t *hash_node);
  81. static void hash_nodes_destroy(rtgui_hash_node_t *hash_node);
  82. static unsigned int primes_closest(unsigned int num);
  83. static void hash_table_needresize(rtgui_hash_table_t *hash_table);
  84. rt_inline unsigned int primes_closest(unsigned int num)
  85. {
  86. int i;
  87. for (i = 0; i < nprimes; i++)
  88. if (primes[i] > num)
  89. return primes[i];
  90. return primes[nprimes - 1];
  91. }
  92. /* directly hash */
  93. unsigned int direct_hash(const void *v)
  94. {
  95. return (unsigned int)v;
  96. }
  97. rtgui_hash_table_t *hash_table_create(rtgui_hash_func_t hash_func, rtgui_equal_func_t key_equal_func)
  98. {
  99. rtgui_hash_table_t *hash_table;
  100. hash_table = (rtgui_hash_table_t *) rtgui_malloc(sizeof(rtgui_hash_table_t));
  101. if (hash_table != RT_NULL)
  102. {
  103. hash_table->size = HASH_TABLE_MIN_SIZE;
  104. hash_table->nnodes = 0;
  105. hash_table->hash_func = hash_func ? hash_func : direct_hash;
  106. hash_table->key_equal_func = key_equal_func;
  107. hash_table->nodes = (rtgui_hash_node_t **)rtgui_malloc(sizeof(rtgui_hash_node_t *) * hash_table->size);
  108. if (hash_table->nodes == RT_NULL)
  109. {
  110. /* no memory yet */
  111. rtgui_free(hash_table);
  112. return RT_NULL;
  113. }
  114. rt_memset(hash_table->nodes, 0, sizeof(rtgui_hash_node_t *) * hash_table->size);
  115. }
  116. return hash_table;
  117. }
  118. void hash_table_destroy(rtgui_hash_table_t *hash_table)
  119. {
  120. unsigned int i;
  121. RT_ASSERT(hash_table != RT_NULL);
  122. for (i = 0; i < hash_table->size; i++)
  123. hash_nodes_destroy(hash_table->nodes[i]);
  124. rtgui_free(hash_table->nodes);
  125. rtgui_free(hash_table);
  126. }
  127. static rtgui_hash_node_t **hash_table_find_node(rtgui_hash_table_t *hash_table, const void *key)
  128. {
  129. rtgui_hash_node_t **node;
  130. node = &hash_table->nodes [(* hash_table->hash_func)(key) % hash_table->size];
  131. if (hash_table->key_equal_func)
  132. while (*node && !(*hash_table->key_equal_func)((*node)->key, key))
  133. node = &(*node)->next;
  134. else
  135. while (*node && (*node)->key != key)
  136. node = &(*node)->next;
  137. return node;
  138. }
  139. void *hash_table_find(rtgui_hash_table_t *hash_table, const void *key)
  140. {
  141. rtgui_hash_node_t *node;
  142. RT_ASSERT(hash_table != RT_NULL);
  143. RT_ASSERT(key != RT_NULL);
  144. node = *hash_table_find_node(hash_table, key);
  145. if (node) return node->value;
  146. else return RT_NULL;
  147. }
  148. void hash_table_insert(rtgui_hash_table_t *hash_table, const void *key, void *value)
  149. {
  150. rtgui_hash_node_t **node;
  151. if (hash_table == RT_NULL)return;
  152. node = hash_table_find_node(hash_table, key);
  153. if (*node)
  154. {
  155. (*node)->value = value;
  156. }
  157. else
  158. {
  159. *node = hash_node_create(key, value);
  160. hash_table->nnodes++;
  161. hash_table_needresize(hash_table);
  162. }
  163. }
  164. rt_bool_t hash_table_remove(rtgui_hash_table_t *hash_table, const void *key)
  165. {
  166. rtgui_hash_node_t **node, *dest;
  167. if (hash_table == RT_NULL) return RT_FALSE;
  168. node = hash_table_find_node(hash_table, key);
  169. if (*node)
  170. {
  171. dest = *node;
  172. (*node) = dest->next;
  173. hash_node_destroy(dest);
  174. hash_table->nnodes--;
  175. hash_table_needresize(hash_table);
  176. return RT_TRUE;
  177. }
  178. return RT_FALSE;
  179. }
  180. void hash_table_foreach(rtgui_hash_table_t *hash_table, rtgui_user_func_t user_func, void *data)
  181. {
  182. rtgui_hash_node_t *node;
  183. int i;
  184. RT_ASSERT(hash_table != RT_NULL);
  185. RT_ASSERT(user_func != RT_NULL);
  186. for (i = 0; i < hash_table->size; i++)
  187. for (node = hash_table->nodes[i]; node; node = node->next)
  188. (* user_func)(node->value, data);
  189. }
  190. unsigned int hash_table_get_size(rtgui_hash_table_t *hash_table)
  191. {
  192. if (hash_table == NULL) return 0;
  193. return hash_table->nnodes;
  194. }
  195. static void hash_table_needresize(rtgui_hash_table_t *hash_table)
  196. {
  197. if ((hash_table->size >= 3 * hash_table->nnodes && hash_table->size > HASH_TABLE_MIN_SIZE) ||
  198. (3 * hash_table->size <= hash_table->nnodes && hash_table->size < HASH_TABLE_MAX_SIZE))
  199. hash_table_resize(hash_table);
  200. }
  201. static void hash_table_resize(rtgui_hash_table_t *hash_table)
  202. {
  203. rtgui_hash_node_t **new_nodes;
  204. rtgui_hash_node_t *node;
  205. rtgui_hash_node_t *next;
  206. unsigned int hash_val;
  207. int new_size;
  208. int i;
  209. i = primes_closest(hash_table->nnodes);
  210. new_size = i > HASH_TABLE_MAX_SIZE ? HASH_TABLE_MAX_SIZE : i < HASH_TABLE_MIN_SIZE ? HASH_TABLE_MIN_SIZE : i ;
  211. new_nodes = (rtgui_hash_node_t **)rtgui_malloc(sizeof(rtgui_hash_node_t *) * new_size);
  212. if (new_nodes == RT_NULL) return; /* no memory yet */
  213. rt_memset(new_nodes, 0, sizeof(rtgui_hash_node_t *) * new_size);
  214. for (i = 0; i < hash_table->size; i++)
  215. {
  216. for (node = hash_table->nodes[i]; node; node = next)
  217. {
  218. next = node->next;
  219. hash_val = (* hash_table->hash_func)(node->key) % new_size;
  220. node->next = new_nodes[hash_val];
  221. new_nodes[hash_val] = node;
  222. }
  223. }
  224. rtgui_free(hash_table->nodes);
  225. hash_table->nodes = new_nodes;
  226. hash_table->size = new_size;
  227. }
  228. static rtgui_hash_node_t *hash_node_create(void *key, void *value)
  229. {
  230. rtgui_hash_node_t *hash_node;
  231. hash_node = (rtgui_hash_node_t *) rtgui_malloc(sizeof(rtgui_hash_node_t));
  232. if (hash_node != RT_NULL)
  233. {
  234. /* set value and key */
  235. hash_node->key = key;
  236. hash_node->value = value;;
  237. hash_node->next = RT_NULL;
  238. }
  239. return hash_node;
  240. }
  241. static void hash_node_destroy(rtgui_hash_node_t *hash_node)
  242. {
  243. rtgui_free(hash_node);
  244. }
  245. static void hash_nodes_destroy(rtgui_hash_node_t *hash_node)
  246. {
  247. if (hash_node)
  248. {
  249. rtgui_hash_node_t *node = hash_node;
  250. rtgui_hash_node_t *temp;
  251. while (node->next)
  252. {
  253. node->key = NULL;
  254. node->value = NULL;
  255. temp = node;
  256. node = node->next;
  257. rtgui_free(temp);
  258. }
  259. node->key = NULL;
  260. node->value = NULL;
  261. rtgui_free(node);
  262. }
  263. }
  264. unsigned int string_hash_func(const void *self)
  265. {
  266. const char *p;
  267. int h = 0, g;
  268. for (p = self; *p != '\0'; p += 1)
  269. {
  270. h = (h << 4) + *p;
  271. if ((g = h & 0xf0000000))
  272. {
  273. h = h ^ (g >> 24);
  274. h = h ^ g;
  275. }
  276. }
  277. return h ;
  278. }
  279. rt_bool_t string_equal_func(const void *a, const void *b)
  280. {
  281. const char *str1, *str2;
  282. str1 = (const char *)a;
  283. str2 = (const char *)b;
  284. if (strcmp(str1, str2) == 0) return RT_TRUE;
  285. return RT_FALSE;
  286. }
  287. static rtgui_hash_table_t *image_hash_table;
  288. static rt_bool_t load_image = RT_FALSE;
  289. void rtgui_system_image_container_init(rt_bool_t load)
  290. {
  291. /* create image hash table */
  292. image_hash_table = hash_table_create(string_hash_func, string_equal_func);
  293. RT_ASSERT(image_hash_table != RT_NULL);
  294. /* set load type */
  295. load_image = load;
  296. }
  297. #ifdef RTGUI_USING_DFS_FILERW
  298. rtgui_image_item_t *rtgui_image_container_get(const char *filename)
  299. {
  300. struct rtgui_image_item *item;
  301. item = hash_table_find(image_hash_table, filename);
  302. if (item == RT_NULL)
  303. {
  304. item = (struct rtgui_image_item *) rtgui_malloc(sizeof(struct rtgui_image_item));
  305. if (item == RT_NULL) return RT_NULL;
  306. /* create a image object */
  307. item->image = rtgui_image_create(filename, load_image);
  308. if (item->image == RT_NULL)
  309. {
  310. rtgui_free(item);
  311. return RT_NULL; /* create image failed */
  312. }
  313. item->refcount = 1;
  314. item->filename = rt_strdup(filename);
  315. hash_table_insert(image_hash_table, item->filename, item);
  316. }
  317. else
  318. {
  319. item->refcount ++; /* increase refcount */
  320. }
  321. return item;
  322. }
  323. #endif
  324. rtgui_image_item_t *rtgui_image_container_get_memref(const char *type, const rt_uint8_t *memory, rt_uint32_t length)
  325. {
  326. char filename[32];
  327. struct rtgui_image_item *item;
  328. /* create filename for image identification */
  329. rt_snprintf(filename, sizeof(filename), "0x%08x_%s", memory, type);
  330. /* search in container */
  331. item = hash_table_find(image_hash_table, filename);
  332. if (item == RT_NULL)
  333. {
  334. item = (struct rtgui_image_item *) rtgui_malloc(sizeof(struct rtgui_image_item));
  335. if (item == RT_NULL) return RT_NULL;
  336. /* create image object */
  337. item->image = rtgui_image_create_from_mem(type, memory, length, load_image);
  338. if (item->image == RT_NULL)
  339. {
  340. rtgui_free(item);
  341. return RT_NULL; /* create image failed */
  342. }
  343. item->refcount = 1;
  344. item->filename = rt_strdup(filename);
  345. hash_table_insert(image_hash_table, item->filename, item);
  346. }
  347. else item->refcount ++;
  348. return item;
  349. }
  350. void rtgui_image_container_put(rtgui_image_item_t *item)
  351. {
  352. item->refcount --;
  353. if (item->refcount == 0)
  354. {
  355. /* remove item from container */
  356. hash_table_remove(image_hash_table, item->filename);
  357. /* destroy image and image item */
  358. rt_free(item->filename);
  359. rtgui_image_destroy(item->image);
  360. rtgui_free(item);
  361. }
  362. }
  363. #endif