image_container.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. /*
  2. * File : image_container.c
  3. * This file is part of RT-Thread GUI Engine
  4. * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. *
  20. * Change Logs:
  21. * Date Author Notes
  22. * 2010-09-15 Bernard first version
  23. */
  24. #include <rtgui/rtgui_system.h>
  25. #include <rtgui/image_container.h>
  26. /*
  27. * ImageContainer is a Image pool to manage image resource in the system.
  28. *
  29. * All of image in the ImageContainer should be loaded in the memory.
  30. * All of image are identified by image file name.
  31. *
  32. * Applications can use rtgui_image_container_get/put to refer or derefer
  33. * a image resource.
  34. */
  35. #if defined(RTGUI_IMAGE_CONTAINER) && defined(RTGUI_USING_DFS_FILERW)
  36. typedef unsigned int (*rtgui_hash_func_t)(const void *key);
  37. typedef struct _rtgui_hash_table rtgui_hash_table_t;
  38. typedef rt_bool_t (*rtgui_equal_func_t)(const void *a, const void *b);
  39. typedef void (*rtgui_user_func_t)(const void *value, const void *data);
  40. /*
  41. *Hash tables
  42. */
  43. rtgui_hash_table_t *hash_table_create(rtgui_hash_func_t hash_func, rtgui_equal_func_t key_equal_func);
  44. void hash_table_destroy(rtgui_hash_table_t *hash_table);
  45. void *hash_table_find(rtgui_hash_table_t *hash_table, const void *key);
  46. void hash_table_insert(rtgui_hash_table_t *hash_table, const void *key, void *value);
  47. rt_bool_t hash_table_remove(rtgui_hash_table_t *hash_table, const void *key);
  48. void hash_table_foreach(rtgui_hash_table_t *hash_table, rtgui_user_func_t user_func, void *data);
  49. unsigned int hash_table_get_size(rtgui_hash_table_t *hash_table);
  50. /* Hash Functions
  51. */
  52. unsigned int direct_hash(const void *v);
  53. #define HASH_TABLE_MIN_SIZE 11
  54. #define HASH_TABLE_MAX_SIZE 6247
  55. typedef struct _gui_hash_node rtgui_hash_node_t;
  56. struct _gui_hash_node
  57. {
  58. const void *key;
  59. void *value;
  60. rtgui_hash_node_t *next;
  61. };
  62. struct _rtgui_hash_table
  63. {
  64. rt_uint16_t size;
  65. rt_uint16_t nnodes;
  66. rtgui_hash_node_t **nodes;
  67. rtgui_hash_func_t hash_func;
  68. rtgui_equal_func_t key_equal_func;
  69. };
  70. static const unsigned int primes[] =
  71. {
  72. 11,
  73. 19,
  74. 37,
  75. 73,
  76. 109,
  77. 163,
  78. 251,
  79. 367,
  80. 557,
  81. 823,
  82. 1237,
  83. 1861,
  84. 2777,
  85. 4177,
  86. 6247,
  87. };
  88. static const unsigned int nprimes = sizeof(primes) / sizeof(primes[0]);
  89. static void hash_table_resize(rtgui_hash_table_t *hash_table);
  90. static rtgui_hash_node_t **hash_table_find_node(rtgui_hash_table_t *hash_table, const void *key);
  91. static rtgui_hash_node_t *hash_node_create(const void *key, void *value);
  92. static void hash_node_destroy(rtgui_hash_node_t *hash_node);
  93. static void hash_nodes_destroy(rtgui_hash_node_t *hash_node);
  94. static unsigned int primes_closest(unsigned int num);
  95. static void hash_table_needresize(rtgui_hash_table_t *hash_table);
  96. rt_inline unsigned int primes_closest(unsigned int num)
  97. {
  98. unsigned int i;
  99. for (i = 0; i < nprimes; i++)
  100. if (primes[i] > num)
  101. return primes[i];
  102. return primes[nprimes - 1];
  103. }
  104. /* directly hash */
  105. unsigned int direct_hash(const void *v)
  106. {
  107. return (unsigned int)v;
  108. }
  109. rtgui_hash_table_t *hash_table_create(rtgui_hash_func_t hash_func, rtgui_equal_func_t key_equal_func)
  110. {
  111. rtgui_hash_table_t *hash_table;
  112. hash_table = (rtgui_hash_table_t *) rtgui_malloc(sizeof(rtgui_hash_table_t));
  113. if (hash_table != RT_NULL)
  114. {
  115. hash_table->size = HASH_TABLE_MIN_SIZE;
  116. hash_table->nnodes = 0;
  117. hash_table->hash_func = hash_func ? hash_func : direct_hash;
  118. hash_table->key_equal_func = key_equal_func;
  119. hash_table->nodes = (rtgui_hash_node_t **)rtgui_malloc(sizeof(rtgui_hash_node_t *) * hash_table->size);
  120. if (hash_table->nodes == RT_NULL)
  121. {
  122. /* no memory yet */
  123. rtgui_free(hash_table);
  124. return RT_NULL;
  125. }
  126. rt_memset(hash_table->nodes, 0, sizeof(rtgui_hash_node_t *) * hash_table->size);
  127. }
  128. return hash_table;
  129. }
  130. void hash_table_destroy(rtgui_hash_table_t *hash_table)
  131. {
  132. unsigned int i;
  133. RT_ASSERT(hash_table != RT_NULL);
  134. for (i = 0; i < hash_table->size; i++)
  135. hash_nodes_destroy(hash_table->nodes[i]);
  136. rtgui_free(hash_table->nodes);
  137. rtgui_free(hash_table);
  138. }
  139. static rtgui_hash_node_t **hash_table_find_node(rtgui_hash_table_t *hash_table, const void *key)
  140. {
  141. rtgui_hash_node_t **node;
  142. node = &hash_table->nodes [(* hash_table->hash_func)(key) % hash_table->size];
  143. if (hash_table->key_equal_func)
  144. while (*node && !(*hash_table->key_equal_func)((*node)->key, key))
  145. node = &(*node)->next;
  146. else
  147. while (*node && (*node)->key != key)
  148. node = &(*node)->next;
  149. return node;
  150. }
  151. void *hash_table_find(rtgui_hash_table_t *hash_table, const void *key)
  152. {
  153. rtgui_hash_node_t *node;
  154. RT_ASSERT(hash_table != RT_NULL);
  155. RT_ASSERT(key != RT_NULL);
  156. node = *hash_table_find_node(hash_table, key);
  157. if (node) return node->value;
  158. else return RT_NULL;
  159. }
  160. void hash_table_insert(rtgui_hash_table_t *hash_table, const void *key, void *value)
  161. {
  162. rtgui_hash_node_t **node;
  163. if (hash_table == RT_NULL)return;
  164. node = hash_table_find_node(hash_table, key);
  165. if (*node)
  166. {
  167. (*node)->value = value;
  168. }
  169. else
  170. {
  171. *node = hash_node_create(key, value);
  172. hash_table->nnodes++;
  173. hash_table_needresize(hash_table);
  174. }
  175. }
  176. rt_bool_t hash_table_remove(rtgui_hash_table_t *hash_table, const void *key)
  177. {
  178. rtgui_hash_node_t **node, *dest;
  179. if (hash_table == RT_NULL) return RT_FALSE;
  180. node = hash_table_find_node(hash_table, key);
  181. if (*node)
  182. {
  183. rt_enter_critical();
  184. dest = *node;
  185. (*node) = dest->next;
  186. hash_node_destroy(dest);
  187. hash_table->nnodes--;
  188. hash_table_needresize(hash_table);
  189. rt_exit_critical();
  190. return RT_TRUE;
  191. }
  192. return RT_FALSE;
  193. }
  194. void hash_table_foreach(rtgui_hash_table_t *hash_table, rtgui_user_func_t user_func, void *data)
  195. {
  196. rtgui_hash_node_t *node;
  197. int i;
  198. RT_ASSERT(hash_table != RT_NULL);
  199. RT_ASSERT(user_func != RT_NULL);
  200. for (i = 0; i < hash_table->size; i++)
  201. for (node = hash_table->nodes[i]; node; node = node->next)
  202. (* user_func)(node->value, data);
  203. }
  204. unsigned int hash_table_get_size(rtgui_hash_table_t *hash_table)
  205. {
  206. if (hash_table == NULL) return 0;
  207. return hash_table->nnodes;
  208. }
  209. static void hash_table_needresize(rtgui_hash_table_t *hash_table)
  210. {
  211. if ((hash_table->size >= 3 * hash_table->nnodes && hash_table->size > HASH_TABLE_MIN_SIZE) ||
  212. (3 * hash_table->size <= hash_table->nnodes && hash_table->size < HASH_TABLE_MAX_SIZE))
  213. hash_table_resize(hash_table);
  214. }
  215. static void hash_table_resize(rtgui_hash_table_t *hash_table)
  216. {
  217. rtgui_hash_node_t **new_nodes;
  218. rtgui_hash_node_t *node;
  219. rtgui_hash_node_t *next;
  220. unsigned int hash_val;
  221. int new_size;
  222. int i;
  223. i = primes_closest(hash_table->nnodes);
  224. new_size = i > HASH_TABLE_MAX_SIZE ? HASH_TABLE_MAX_SIZE : i < HASH_TABLE_MIN_SIZE ? HASH_TABLE_MIN_SIZE : i ;
  225. new_nodes = (rtgui_hash_node_t **)rtgui_malloc(sizeof(rtgui_hash_node_t *) * new_size);
  226. if (new_nodes == RT_NULL) return; /* no memory yet */
  227. rt_memset(new_nodes, 0, sizeof(rtgui_hash_node_t *) * new_size);
  228. for (i = 0; i < hash_table->size; i++)
  229. {
  230. for (node = hash_table->nodes[i]; node; node = next)
  231. {
  232. next = node->next;
  233. hash_val = (* hash_table->hash_func)(node->key) % new_size;
  234. node->next = new_nodes[hash_val];
  235. new_nodes[hash_val] = node;
  236. }
  237. }
  238. rtgui_free(hash_table->nodes);
  239. hash_table->nodes = new_nodes;
  240. hash_table->size = new_size;
  241. }
  242. static rtgui_hash_node_t *hash_node_create(const void *key, void *value)
  243. {
  244. rtgui_hash_node_t *hash_node;
  245. hash_node = (rtgui_hash_node_t *) rtgui_malloc(sizeof(rtgui_hash_node_t));
  246. if (hash_node != RT_NULL)
  247. {
  248. /* set value and key */
  249. hash_node->key = key;
  250. hash_node->value = value;;
  251. hash_node->next = RT_NULL;
  252. }
  253. return hash_node;
  254. }
  255. static void hash_node_destroy(rtgui_hash_node_t *hash_node)
  256. {
  257. rtgui_free(hash_node);
  258. }
  259. static void hash_nodes_destroy(rtgui_hash_node_t *hash_node)
  260. {
  261. if (hash_node)
  262. {
  263. rtgui_hash_node_t *node = hash_node;
  264. rtgui_hash_node_t *temp;
  265. while (node->next)
  266. {
  267. node->key = NULL;
  268. node->value = NULL;
  269. temp = node;
  270. node = node->next;
  271. rtgui_free(temp);
  272. }
  273. node->key = NULL;
  274. node->value = NULL;
  275. rtgui_free(node);
  276. }
  277. }
  278. unsigned int string_hash_func(const void *self)
  279. {
  280. const char *p;
  281. int h = 0, g;
  282. for (p = self; *p != '\0'; p += 1)
  283. {
  284. h = (h << 4) + *p;
  285. g = h;
  286. if (g & 0xf0000000)
  287. {
  288. h = h ^ (g >> 24);
  289. h = h ^ g;
  290. }
  291. }
  292. return h ;
  293. }
  294. rt_bool_t string_equal_func(const void *a, const void *b)
  295. {
  296. const char *str1, *str2;
  297. str1 = (const char *)a;
  298. str2 = (const char *)b;
  299. if (strcmp(str1, str2) == 0) return RT_TRUE;
  300. return RT_FALSE;
  301. }
  302. static rtgui_hash_table_t *image_hash_table;
  303. static struct rt_mutex _image_hash_lock;
  304. void rtgui_system_image_container_init(void)
  305. {
  306. rt_mutex_init(&_image_hash_lock, "image", RT_IPC_FLAG_FIFO);
  307. /* create image hash table */
  308. image_hash_table = hash_table_create(string_hash_func, string_equal_func);
  309. RT_ASSERT(image_hash_table != RT_NULL);
  310. }
  311. rtgui_image_item_t *rtgui_image_container_get(const char *filename)
  312. {
  313. struct rtgui_image_item *item = RT_NULL;
  314. if (rt_mutex_take(&_image_hash_lock, RT_WAITING_FOREVER) == RT_EOK)
  315. {
  316. item = hash_table_find(image_hash_table, filename);
  317. if (item == RT_NULL)
  318. {
  319. item = (struct rtgui_image_item *) rtgui_malloc(sizeof(struct rtgui_image_item));
  320. if (item == RT_NULL)
  321. {
  322. rt_mutex_release(&_image_hash_lock);
  323. return RT_NULL;
  324. }
  325. /* create a image object */
  326. item->image = rtgui_image_create(filename, RT_TRUE);
  327. if (item->image == RT_NULL)
  328. {
  329. rtgui_free(item);
  330. rt_mutex_release(&_image_hash_lock);
  331. return RT_NULL; /* create image failed */
  332. }
  333. item->refcount = 1;
  334. item->filename = rt_strdup(filename);
  335. hash_table_insert(image_hash_table, item->filename, item);
  336. }
  337. else
  338. {
  339. item->refcount ++; /* increase refcount */
  340. }
  341. rt_mutex_release(&_image_hash_lock);
  342. }
  343. return item;
  344. }
  345. RTM_EXPORT(rtgui_image_container_get);
  346. void rtgui_image_container_put(rtgui_image_item_t *item)
  347. {
  348. rt_mutex_take(&_image_hash_lock, RT_WAITING_FOREVER);
  349. item->refcount --;
  350. if (item->refcount == 0)
  351. {
  352. /* remove item from container */
  353. hash_table_remove(image_hash_table, item->filename);
  354. /* destroy image and image item */
  355. rt_free(item->filename);
  356. rtgui_image_destroy(item->image);
  357. rtgui_free(item);
  358. }
  359. rt_mutex_release(&_image_hash_lock);
  360. }
  361. RTM_EXPORT(rtgui_image_container_put);
  362. #endif