File Coverage

lru.c
Criterion Covered Total %
statement 55 56 98.2
branch 91 136 66.9
condition n/a
subroutine n/a
pod n/a
total 146 192 76.0


line stmt bran cond sub pod time code
1             #include
2             #include "gmem.h"
3             #include "lru.h"
4              
5 27           Cache* cache_build(pTHX_ int capacity)
6             {
7             Cache* cache;
8 27           GMEM_NEW(cache, Cache*, sizeof(Cache));
9 27 50         if (cache) {
10 27           cache->capacity = capacity;
11 27           cache->data = NULL;
12             }
13 27           return cache;
14             }
15              
16 27           void cache_destroy(pTHX_ Cache* cache)
17             {
18 27           cache_clear(aTHX_ cache);
19             #if defined(GMEM_CHECK)
20             assert(HASH_COUNT(cache->data) == 0);
21             #endif
22 27           GMEM_DEL(cache, Cache*, sizeof(Cache));
23 27           }
24              
25 9           int cache_size(pTHX_ Cache* cache)
26             {
27 9 100         return HASH_COUNT(cache->data);
28             }
29              
30 2           int cache_capacity(pTHX_ Cache* cache)
31             {
32 2           return cache->capacity;
33             }
34              
35 2435           static void clear_entry(pTHX_ Cache* cache, CacheEntry* entry)
36             {
37 2435           SvREFCNT_dec(entry->key);
38 2435           SvREFCNT_dec(entry->val);
39 2435 50         HASH_DELETE(hh, cache->data, entry);
    100          
    50          
    50          
    50          
    100          
    100          
    100          
40 2435           free(entry);
41 2435           }
42              
43 29           void cache_clear(pTHX_ Cache* cache)
44             {
45             CacheEntry* entry;
46             CacheEntry* tmp;
47 2064 100         HASH_ITER(hh, cache->data, entry, tmp) {
    100          
    100          
48 2035           clear_entry(aTHX_ cache, entry);
49             }
50 29           }
51              
52 2430           SV* cache_find(pTHX_ Cache* cache, SV* key)
53             {
54 2430           STRLEN klen = 0;
55 2430           char* kptr = NULL;
56 2430           kptr = SvPV(key, klen);
57             /* fprintf(stderr, "FIND KEY %lu [%s]\n", klen, kptr); */
58              
59             CacheEntry* entry;
60 11933 100         HASH_FIND(hh, cache->data, kptr, klen, entry);
    50          
    100          
    100          
    50          
    50          
    100          
    100          
61 2430 100         if (!entry) {
62             /* return NULL; */
63 412           return &PL_sv_undef;
64             }
65              
66             /*
67             * remove it; the subsequent add will throw it on the front of the list
68             */
69 2018 50         HASH_DELETE(hh, cache->data, entry);
    100          
    50          
    50          
    50          
    100          
    100          
    100          
70 4019 100         HASH_ADD_KEYPTR(hh, cache->data, kptr, klen, entry);
    100          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
71              
72 2018           return entry->val;
73             }
74              
75 2435           int cache_add(pTHX_ Cache* cache, SV* key, SV* val)
76             {
77 2435           CacheEntry* entry = (CacheEntry*) malloc(sizeof(CacheEntry));
78 2435 50         if (!entry) {
79 0           return 0;
80             }
81              
82             #if 0
83             /*
84             * This version simply increments the refcnt for key and val.
85             * It is MUCH faster, and it would be awesome if we could use it.
86             * BUT
87             * Depending on how the key value was declared / used in Perl,
88             * we have no guarantees that we will NOT overwrite data in the cache.
89             */
90             entry->key = key;
91             entry->val = val;
92             SvREFCNT_inc(entry->key);
93             SvREFCNT_inc(entry->val);
94             #elif 1
95             /*
96             * This version creates SV* copies of key and val.
97             * It is MUCH slower, but it might be the (only) correct way to do it.
98             */
99 2435           entry->key = newSVsv(key);
100 2435           entry->val = newSVsv(val);
101             #else
102             /*
103             * This version creates SV* copies of key only.
104             * It is slower, and maybe it works...
105             */
106             entry->key = newSVsv(key);
107             entry->val = val;
108             SvREFCNT_inc(entry->val);
109             #endif
110              
111             /* do not use gmem for these elements,
112             * they will be deleted internally by ut */
113 2435           STRLEN klen = 0;
114 2435           char* kptr = NULL;
115 2435           kptr = SvPV(entry->key, klen);
116             /* fprintf(stderr, "ADD KEY %lu [%s]\n", klen, kptr); */
117              
118 5107 100         HASH_ADD_KEYPTR(hh, cache->data, kptr, klen, entry);
    100          
    50          
    50          
    100          
    100          
    50          
    50          
    50          
    100          
    100          
    100          
    100          
    50          
    50          
119              
120             /*
121             * prune the cache to not exceed its size
122             */
123 2435 50         int size = HASH_COUNT(cache->data);
124             int j;
125 2835 100         for (j = cache->capacity; j < size; ++j) {
126             CacheEntry* tmp;
127 400 50         HASH_ITER(hh, cache->data, entry, tmp) {
    50          
128             /*
129             * prune the first entry; loop is based on insertion
130             * order so this deletes the oldest item
131             */
132              
133 400           clear_entry(aTHX_ cache, entry);
134 400           break;
135             }
136             }
137              
138 2435           return 1;
139             }
140              
141 2           void cache_iterate(pTHX_ Cache* cache, CacheVisitor visitor, void* arg)
142             {
143 2           CacheEntry* entry = NULL;
144 2           CacheEntry* tmp = NULL;
145 17 50         HASH_ITER(hh, cache->data, entry, tmp) {
    100          
    100          
146 15           visitor(cache, entry, arg);
147             }
148 2           }