| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- /*
- * File : image_container.c
- * This file is part of RT-Thread GUI Engine
- * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Change Logs:
- * Date Author Notes
- * 2010-09-15 Bernard first version
- */
- #include <rtgui/rtgui_system.h>
- #include <rtgui/image_container.h>
- /*
- * ImageContainer is a Image pool to manage image resource in the system.
- *
- * All of image in the ImageContainer should be loaded in the memory.
- * All of image are identified by image file name.
- *
- * Applications can use rtgui_image_container_get/put to refer or derefer
- * a image resource.
- */
- #if defined(RTGUI_IMAGE_CONTAINER) && defined(RTGUI_USING_DFS_FILERW)
- typedef unsigned int (*rtgui_hash_func_t)(const void *key);
- typedef struct _rtgui_hash_table rtgui_hash_table_t;
- typedef rt_bool_t (*rtgui_equal_func_t)(const void *a, const void *b);
- typedef void (*rtgui_user_func_t)(const void *value, const void *data);
- /*
- *Hash tables
- */
- rtgui_hash_table_t *hash_table_create(rtgui_hash_func_t hash_func, rtgui_equal_func_t key_equal_func);
- void hash_table_destroy(rtgui_hash_table_t *hash_table);
- void *hash_table_find(rtgui_hash_table_t *hash_table, const void *key);
- void hash_table_insert(rtgui_hash_table_t *hash_table, const void *key, void *value);
- rt_bool_t hash_table_remove(rtgui_hash_table_t *hash_table, const void *key);
- void hash_table_foreach(rtgui_hash_table_t *hash_table, rtgui_user_func_t user_func, void *data);
- unsigned int hash_table_get_size(rtgui_hash_table_t *hash_table);
- /* Hash Functions
- */
- unsigned int direct_hash(const void *v);
- #define HASH_TABLE_MIN_SIZE 11
- #define HASH_TABLE_MAX_SIZE 6247
- typedef struct _gui_hash_node rtgui_hash_node_t;
- struct _gui_hash_node
- {
- const void *key;
- void *value;
- rtgui_hash_node_t *next;
- };
- struct _rtgui_hash_table
- {
- rt_uint16_t size;
- rt_uint16_t nnodes;
- rtgui_hash_node_t **nodes;
- rtgui_hash_func_t hash_func;
- rtgui_equal_func_t key_equal_func;
- };
- static const unsigned int primes[] =
- {
- 11,
- 19,
- 37,
- 73,
- 109,
- 163,
- 251,
- 367,
- 557,
- 823,
- 1237,
- 1861,
- 2777,
- 4177,
- 6247,
- };
- static const unsigned int nprimes = sizeof(primes) / sizeof(primes[0]);
- static void hash_table_resize(rtgui_hash_table_t *hash_table);
- static rtgui_hash_node_t **hash_table_find_node(rtgui_hash_table_t *hash_table, const void *key);
- static rtgui_hash_node_t *hash_node_create(const void *key, void *value);
- static void hash_node_destroy(rtgui_hash_node_t *hash_node);
- static void hash_nodes_destroy(rtgui_hash_node_t *hash_node);
- static unsigned int primes_closest(unsigned int num);
- static void hash_table_needresize(rtgui_hash_table_t *hash_table);
- rt_inline unsigned int primes_closest(unsigned int num)
- {
- unsigned int i;
- for (i = 0; i < nprimes; i++)
- if (primes[i] > num)
- return primes[i];
- return primes[nprimes - 1];
- }
- /* directly hash */
- unsigned int direct_hash(const void *v)
- {
- return (unsigned int)v;
- }
- rtgui_hash_table_t *hash_table_create(rtgui_hash_func_t hash_func, rtgui_equal_func_t key_equal_func)
- {
- rtgui_hash_table_t *hash_table;
- hash_table = (rtgui_hash_table_t *) rtgui_malloc(sizeof(rtgui_hash_table_t));
- if (hash_table != RT_NULL)
- {
- hash_table->size = HASH_TABLE_MIN_SIZE;
- hash_table->nnodes = 0;
- hash_table->hash_func = hash_func ? hash_func : direct_hash;
- hash_table->key_equal_func = key_equal_func;
- hash_table->nodes = (rtgui_hash_node_t **)rtgui_malloc(sizeof(rtgui_hash_node_t *) * hash_table->size);
- if (hash_table->nodes == RT_NULL)
- {
- /* no memory yet */
- rtgui_free(hash_table);
- return RT_NULL;
- }
- rt_memset(hash_table->nodes, 0, sizeof(rtgui_hash_node_t *) * hash_table->size);
- }
- return hash_table;
- }
- void hash_table_destroy(rtgui_hash_table_t *hash_table)
- {
- unsigned int i;
- RT_ASSERT(hash_table != RT_NULL);
- for (i = 0; i < hash_table->size; i++)
- hash_nodes_destroy(hash_table->nodes[i]);
- rtgui_free(hash_table->nodes);
- rtgui_free(hash_table);
- }
- static rtgui_hash_node_t **hash_table_find_node(rtgui_hash_table_t *hash_table, const void *key)
- {
- rtgui_hash_node_t **node;
- node = &hash_table->nodes [(* hash_table->hash_func)(key) % hash_table->size];
- if (hash_table->key_equal_func)
- while (*node && !(*hash_table->key_equal_func)((*node)->key, key))
- node = &(*node)->next;
- else
- while (*node && (*node)->key != key)
- node = &(*node)->next;
- return node;
- }
- void *hash_table_find(rtgui_hash_table_t *hash_table, const void *key)
- {
- rtgui_hash_node_t *node;
- RT_ASSERT(hash_table != RT_NULL);
- RT_ASSERT(key != RT_NULL);
- node = *hash_table_find_node(hash_table, key);
- if (node) return node->value;
- else return RT_NULL;
- }
- void hash_table_insert(rtgui_hash_table_t *hash_table, const void *key, void *value)
- {
- rtgui_hash_node_t **node;
- if (hash_table == RT_NULL)return;
- node = hash_table_find_node(hash_table, key);
- if (*node)
- {
- (*node)->value = value;
- }
- else
- {
- *node = hash_node_create(key, value);
- hash_table->nnodes++;
- hash_table_needresize(hash_table);
- }
- }
- rt_bool_t hash_table_remove(rtgui_hash_table_t *hash_table, const void *key)
- {
- rtgui_hash_node_t **node, *dest;
- if (hash_table == RT_NULL) return RT_FALSE;
- node = hash_table_find_node(hash_table, key);
- if (*node)
- {
- rt_enter_critical();
- dest = *node;
- (*node) = dest->next;
- hash_node_destroy(dest);
- hash_table->nnodes--;
- hash_table_needresize(hash_table);
- rt_exit_critical();
- return RT_TRUE;
- }
- return RT_FALSE;
- }
- void hash_table_foreach(rtgui_hash_table_t *hash_table, rtgui_user_func_t user_func, void *data)
- {
- rtgui_hash_node_t *node;
- int i;
- RT_ASSERT(hash_table != RT_NULL);
- RT_ASSERT(user_func != RT_NULL);
- for (i = 0; i < hash_table->size; i++)
- for (node = hash_table->nodes[i]; node; node = node->next)
- (* user_func)(node->value, data);
- }
- unsigned int hash_table_get_size(rtgui_hash_table_t *hash_table)
- {
- if (hash_table == NULL) return 0;
- return hash_table->nnodes;
- }
- static void hash_table_needresize(rtgui_hash_table_t *hash_table)
- {
- if ((hash_table->size >= 3 * hash_table->nnodes && hash_table->size > HASH_TABLE_MIN_SIZE) ||
- (3 * hash_table->size <= hash_table->nnodes && hash_table->size < HASH_TABLE_MAX_SIZE))
- hash_table_resize(hash_table);
- }
- static void hash_table_resize(rtgui_hash_table_t *hash_table)
- {
- rtgui_hash_node_t **new_nodes;
- rtgui_hash_node_t *node;
- rtgui_hash_node_t *next;
- unsigned int hash_val;
- int new_size;
- int i;
- i = primes_closest(hash_table->nnodes);
- new_size = i > HASH_TABLE_MAX_SIZE ? HASH_TABLE_MAX_SIZE : i < HASH_TABLE_MIN_SIZE ? HASH_TABLE_MIN_SIZE : i ;
- new_nodes = (rtgui_hash_node_t **)rtgui_malloc(sizeof(rtgui_hash_node_t *) * new_size);
- if (new_nodes == RT_NULL) return; /* no memory yet */
- rt_memset(new_nodes, 0, sizeof(rtgui_hash_node_t *) * new_size);
- for (i = 0; i < hash_table->size; i++)
- {
- for (node = hash_table->nodes[i]; node; node = next)
- {
- next = node->next;
- hash_val = (* hash_table->hash_func)(node->key) % new_size;
- node->next = new_nodes[hash_val];
- new_nodes[hash_val] = node;
- }
- }
- rtgui_free(hash_table->nodes);
- hash_table->nodes = new_nodes;
- hash_table->size = new_size;
- }
- static rtgui_hash_node_t *hash_node_create(const void *key, void *value)
- {
- rtgui_hash_node_t *hash_node;
- hash_node = (rtgui_hash_node_t *) rtgui_malloc(sizeof(rtgui_hash_node_t));
- if (hash_node != RT_NULL)
- {
- /* set value and key */
- hash_node->key = key;
- hash_node->value = value;;
- hash_node->next = RT_NULL;
- }
- return hash_node;
- }
- static void hash_node_destroy(rtgui_hash_node_t *hash_node)
- {
- rtgui_free(hash_node);
- }
- static void hash_nodes_destroy(rtgui_hash_node_t *hash_node)
- {
- if (hash_node)
- {
- rtgui_hash_node_t *node = hash_node;
- rtgui_hash_node_t *temp;
- while (node->next)
- {
- node->key = NULL;
- node->value = NULL;
- temp = node;
- node = node->next;
- rtgui_free(temp);
- }
- node->key = NULL;
- node->value = NULL;
- rtgui_free(node);
- }
- }
- unsigned int string_hash_func(const void *self)
- {
- const char *p;
- int h = 0, g;
- for (p = self; *p != '\0'; p += 1)
- {
- h = (h << 4) + *p;
- g = h;
- if (g & 0xf0000000)
- {
- h = h ^ (g >> 24);
- h = h ^ g;
- }
- }
- return h ;
- }
- rt_bool_t string_equal_func(const void *a, const void *b)
- {
- const char *str1, *str2;
- str1 = (const char *)a;
- str2 = (const char *)b;
- if (strcmp(str1, str2) == 0) return RT_TRUE;
- return RT_FALSE;
- }
- static rtgui_hash_table_t *image_hash_table;
- static struct rt_mutex _image_hash_lock;
- void rtgui_system_image_container_init(void)
- {
- rt_mutex_init(&_image_hash_lock, "image", RT_IPC_FLAG_FIFO);
- /* create image hash table */
- image_hash_table = hash_table_create(string_hash_func, string_equal_func);
- RT_ASSERT(image_hash_table != RT_NULL);
- }
- rtgui_image_item_t *rtgui_image_container_get(const char *filename)
- {
- struct rtgui_image_item *item = RT_NULL;
- if (rt_mutex_take(&_image_hash_lock, RT_WAITING_FOREVER) == RT_EOK)
- {
- item = hash_table_find(image_hash_table, filename);
- if (item == RT_NULL)
- {
- item = (struct rtgui_image_item *) rtgui_malloc(sizeof(struct rtgui_image_item));
- if (item == RT_NULL)
- {
- rt_mutex_release(&_image_hash_lock);
- return RT_NULL;
- }
- /* create a image object */
- item->image = rtgui_image_create(filename, RT_TRUE);
- if (item->image == RT_NULL)
- {
- rtgui_free(item);
- rt_mutex_release(&_image_hash_lock);
- return RT_NULL; /* create image failed */
- }
- item->refcount = 1;
- item->filename = rt_strdup(filename);
- hash_table_insert(image_hash_table, item->filename, item);
- }
- else
- {
- item->refcount ++; /* increase refcount */
- }
- rt_mutex_release(&_image_hash_lock);
- }
- return item;
- }
- RTM_EXPORT(rtgui_image_container_get);
- void rtgui_image_container_put(rtgui_image_item_t *item)
- {
- rt_mutex_take(&_image_hash_lock, RT_WAITING_FOREVER);
- item->refcount --;
- if (item->refcount == 0)
- {
- /* remove item from container */
- hash_table_remove(image_hash_table, item->filename);
- /* destroy image and image item */
- rt_free(item->filename);
- rtgui_image_destroy(item->image);
- rtgui_free(item);
- }
- rt_mutex_release(&_image_hash_lock);
- }
- RTM_EXPORT(rtgui_image_container_put);
- #endif
|