summaryrefslogtreecommitdiff
path: root/src/lib/evas/common/evas_common_generic_cache.c
blob: ddb055deb291150a5a48a587524eb6938bc6d780 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include "evas_common_private.h"

EAPI Generic_Cache*
generic_cache_new(void *user_data, Generic_Cache_Free func)
{
   Generic_Cache *cache;
   cache = calloc(1, sizeof(Generic_Cache));
   cache->hash = eina_hash_int32_new(NULL);
   cache->user_data = user_data;
   cache->free_func = func;
   return cache;
}

EAPI void
generic_cache_destroy(Generic_Cache *cache)
{
   generic_cache_dump(cache);
   eina_hash_free(cache->hash);
}

EAPI void
generic_cache_dump(Generic_Cache *cache)
{
   Generic_Cache_Entry *entry;
   if (cache)
     {
        eina_hash_free_buckets(cache->hash);
        EINA_LIST_FREE(cache->lru_list, entry)
          {
             cache->free_func(cache->user_data, entry->data);
             free(entry);
          }
     }
}

EAPI void
generic_cache_data_set(Generic_Cache *cache, void *key, void *surface)
{
   Generic_Cache_Entry *entry = NULL;
   int count;

   entry = calloc(1, sizeof(Generic_Cache_Entry));
   entry->key = key;
   entry->data = surface;
   entry->ref = 1;
   eina_hash_add(cache->hash, &key, entry);
   cache->lru_list = eina_list_prepend(cache->lru_list, entry);
   count = eina_list_count(cache->lru_list);
   if (count > 50)
   {
      entry = eina_list_data_get(eina_list_last(cache->lru_list));
      // if its still being ref.
      if (entry->ref > 1) return;
      eina_hash_del(cache->hash, &entry->key, entry);
      cache->lru_list = eina_list_remove_list(cache->lru_list, eina_list_last(cache->lru_list));
      cache->free_func(cache->user_data, entry->data);
      free(entry);
   }
}

EAPI void *
generic_cache_data_get(Generic_Cache *cache, void *key)
{
   Generic_Cache_Entry *entry = NULL, *lru_data;
   Eina_List *l;

   entry =  eina_hash_find(cache->hash, &key);
   if (entry)
     {
        // update the ref
        entry->ref += 1;
        // promote in lru
        EINA_LIST_FOREACH(cache->lru_list, l, lru_data)
          {
            if (lru_data == entry)
              {
                 cache->lru_list = eina_list_promote_list(cache->lru_list, l);
                 break;
              }
          }
        return entry->data;
     }
   return NULL;
}

EAPI void
generic_cache_data_drop(Generic_Cache *cache, void *key)
{
   Generic_Cache_Entry *entry = NULL;

   entry =  eina_hash_find(cache->hash, &key);
   if (entry)
     {
        entry->ref -= 1;
        // if its still being ref.
        if (entry->ref) return;
        eina_hash_del(cache->hash, &entry->key, entry);
        // find and remove from lru list
        cache->lru_list = eina_list_remove(cache->lru_list, entry);
        cache->free_func(cache->user_data, entry->data);
        free(entry);
     }
}