Skip to content

Commit 95967b5

Browse files
committed
Implement LRU cache
1 parent bf3c487 commit 95967b5

File tree

2 files changed

+128
-3
lines changed

2 files changed

+128
-3
lines changed

ext/bcmath/bcmath.c

Lines changed: 114 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
ZEND_DECLARE_MODULE_GLOBALS(bcmath)
3333
static PHP_GINIT_FUNCTION(bcmath);
3434
static PHP_GSHUTDOWN_FUNCTION(bcmath);
35+
static PHP_RINIT_FUNCTION(bcmath);
36+
static PHP_RSHUTDOWN_FUNCTION(bcmath);
3537
static PHP_MINIT_FUNCTION(bcmath);
3638
static PHP_MSHUTDOWN_FUNCTION(bcmath);
3739
static PHP_MINFO_FUNCTION(bcmath);
@@ -42,8 +44,8 @@ zend_module_entry bcmath_module_entry = {
4244
ext_functions,
4345
PHP_MINIT(bcmath),
4446
PHP_MSHUTDOWN(bcmath),
45-
NULL,
46-
NULL,
47+
PHP_RINIT(bcmath),
48+
PHP_RSHUTDOWN(bcmath),
4749
PHP_MINFO(bcmath),
4850
PHP_BCMATH_VERSION,
4951
PHP_MODULE_GLOBALS(bcmath),
@@ -82,6 +84,93 @@ PHP_INI_BEGIN()
8284
PHP_INI_END()
8385
/* }}} */
8486

87+
static void bcmath_destroy_lru_entry(php_bc_lru_entry *entry)
88+
{
89+
/* No need to clean up str as that reference is held by the table. */
90+
bc_free_num(&entry->num);
91+
}
92+
93+
static void bcmath_lru_init(php_bc_lru_cache *cache)
94+
{
95+
cache->head = cache->tail = NULL;
96+
zend_hash_init(&cache->table, PHP_BCMATH_LRU_SIZE, NULL, NULL, false);
97+
zend_hash_real_init_mixed(&cache->table);
98+
}
99+
100+
static void bcmath_lru_destroy(php_bc_lru_cache *cache)
101+
{
102+
php_bc_lru_entry *entry;
103+
ZEND_HASH_MAP_FOREACH_PTR(&cache->table, entry) {
104+
bcmath_destroy_lru_entry(entry);
105+
efree(entry);
106+
} ZEND_HASH_FOREACH_END();
107+
zend_hash_destroy(&cache->table);
108+
}
109+
110+
static void bcmath_lru_new_entry(php_bc_lru_cache *cache, zend_string *str, bc_num num)
111+
{
112+
php_bc_lru_entry *entry = emalloc(sizeof(*entry));
113+
entry->str = str;
114+
entry->num = num;
115+
116+
entry->next = cache->head;
117+
entry->prev = NULL;
118+
119+
if (cache->head) {
120+
cache->head->prev = entry;
121+
} else {
122+
cache->tail = entry;
123+
}
124+
125+
cache->head = entry;
126+
127+
zend_hash_add_new_ptr(&cache->table, str, entry);
128+
}
129+
130+
static void bcmath_lru_move_to_head(php_bc_lru_cache *cache, php_bc_lru_entry *entry)
131+
{
132+
if (entry == cache->head) {
133+
return;
134+
}
135+
136+
if (entry == cache->tail) {
137+
cache->tail = entry->prev;
138+
}
139+
140+
if (entry->prev) {
141+
entry->prev->next = entry->next;
142+
}
143+
144+
if (entry->next) {
145+
entry->next->prev = entry->prev;
146+
}
147+
148+
entry->next = cache->head;
149+
entry->prev = NULL;
150+
151+
cache->head->prev = entry;
152+
cache->head = entry;
153+
}
154+
155+
static void bcmath_lru_evict_oldest_and_reuse(php_bc_lru_cache *cache, zend_string *str, bc_num num)
156+
{
157+
zend_hash_del(&cache->table, cache->tail->str);
158+
bcmath_destroy_lru_entry(cache->tail);
159+
cache->tail->str = str;
160+
cache->tail->num = num;
161+
zend_hash_add_new_ptr(&cache->table, str, cache->tail);
162+
bcmath_lru_move_to_head(cache, cache->tail);
163+
}
164+
165+
static void bcmath_lru_add(php_bc_lru_cache *cache, zend_string *str, bc_num num)
166+
{
167+
if (zend_hash_num_elements(&cache->table) == PHP_BCMATH_LRU_SIZE) {
168+
bcmath_lru_evict_oldest_and_reuse(cache, str, num);
169+
} else {
170+
bcmath_lru_new_entry(cache, str, num);
171+
}
172+
}
173+
85174
/* {{{ PHP_GINIT_FUNCTION */
86175
static PHP_GINIT_FUNCTION(bcmath)
87176
{
@@ -102,6 +191,18 @@ static PHP_GSHUTDOWN_FUNCTION(bcmath)
102191
}
103192
/* }}} */
104193

194+
static PHP_RINIT_FUNCTION(bcmath)
195+
{
196+
bcmath_lru_init(&bcmath_globals.lru_cache);
197+
return SUCCESS;
198+
}
199+
200+
static PHP_RSHUTDOWN_FUNCTION(bcmath)
201+
{
202+
bcmath_lru_destroy(&bcmath_globals.lru_cache);
203+
return SUCCESS;
204+
}
205+
105206
/* {{{ PHP_MINIT_FUNCTION */
106207
PHP_MINIT_FUNCTION(bcmath)
107208
{
@@ -132,12 +233,22 @@ PHP_MINFO_FUNCTION(bcmath)
132233

133234
/* {{{ php_str2num
134235
Convert to bc_num detecting scale */
135-
static zend_result php_str2num(bc_num *num, const zend_string *str)
236+
static zend_result php_str2num(bc_num *num, zend_string *str)
136237
{
238+
php_bc_lru_cache *cache = &BCG(lru_cache);
239+
php_bc_lru_entry *cache_entry = zend_hash_find_ptr(&cache->table, str);
240+
if (cache_entry) {
241+
bcmath_lru_move_to_head(cache, cache_entry);
242+
*num = bc_copy_num(cache_entry->num);
243+
return SUCCESS;
244+
}
245+
137246
if (!bc_str2num(num, ZSTR_VAL(str), ZSTR_VAL(str) + ZSTR_LEN(str), 0, true)) {
138247
return FAILURE;
139248
}
140249

250+
bcmath_lru_add(cache, str, bc_copy_num(*num));
251+
141252
return SUCCESS;
142253
}
143254
/* }}} */

ext/bcmath/php_bcmath.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,31 @@
2121
#include "zend_API.h"
2222
#include "ext/standard/php_math_round_mode.h"
2323

24+
#define PHP_BCMATH_LRU_SIZE 16
25+
2426
extern zend_module_entry bcmath_module_entry;
2527
#define phpext_bcmath_ptr &bcmath_module_entry
2628

2729
#include "php_version.h"
2830
#define PHP_BCMATH_VERSION PHP_VERSION
2931

32+
typedef struct php_bc_lru_entry {
33+
zend_string *str;
34+
bc_num num;
35+
struct php_bc_lru_entry *prev, *next;
36+
} php_bc_lru_entry;
37+
38+
typedef struct php_bc_lru_cache {
39+
HashTable table;
40+
php_bc_lru_entry *head, *tail;
41+
} php_bc_lru_cache;
42+
3043
ZEND_BEGIN_MODULE_GLOBALS(bcmath)
3144
bc_num _zero_;
3245
bc_num _one_;
3346
bc_num _two_;
3447
int bc_precision;
48+
php_bc_lru_cache lru_cache;
3549
ZEND_END_MODULE_GLOBALS(bcmath)
3650

3751
#if defined(ZTS) && defined(COMPILE_DL_BCMATH)

0 commit comments

Comments
 (0)