Skip to content

Commit 04c6918

Browse files
committed
Implement LRU cache
1 parent a66439a commit 04c6918

File tree

2 files changed

+147
-22
lines changed

2 files changed

+147
-22
lines changed

ext/bcmath/bcmath.c

Lines changed: 133 additions & 22 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, char *str)
236+
static zend_result php_str2num(bc_num *num, zend_string *str)
136237
{
137-
if (!bc_str2num(num, str, 0, true)) {
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+
246+
if (!bc_str2num(num, ZSTR_VAL(str), 0, true)) {
138247
return FAILURE;
139248
}
140249

250+
bcmath_lru_add(cache, str, bc_copy_num(*num));
251+
141252
return SUCCESS;
142253
}
143254
/* }}} */
@@ -169,12 +280,12 @@ PHP_FUNCTION(bcadd)
169280

170281
bc_init_num(&result);
171282

172-
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
283+
if (php_str2num(&first, left) == FAILURE) {
173284
zend_argument_value_error(1, "is not well-formed");
174285
goto cleanup;
175286
}
176287

177-
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
288+
if (php_str2num(&second, right) == FAILURE) {
178289
zend_argument_value_error(2, "is not well-formed");
179290
goto cleanup;
180291
}
@@ -218,12 +329,12 @@ PHP_FUNCTION(bcsub)
218329

219330
bc_init_num(&result);
220331

221-
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
332+
if (php_str2num(&first, left) == FAILURE) {
222333
zend_argument_value_error(1, "is not well-formed");
223334
goto cleanup;
224335
}
225336

226-
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
337+
if (php_str2num(&second, right) == FAILURE) {
227338
zend_argument_value_error(2, "is not well-formed");
228339
goto cleanup;
229340
}
@@ -267,12 +378,12 @@ PHP_FUNCTION(bcmul)
267378

268379
bc_init_num(&result);
269380

270-
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
381+
if (php_str2num(&first, left) == FAILURE) {
271382
zend_argument_value_error(1, "is not well-formed");
272383
goto cleanup;
273384
}
274385

275-
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
386+
if (php_str2num(&second, right) == FAILURE) {
276387
zend_argument_value_error(2, "is not well-formed");
277388
goto cleanup;
278389
}
@@ -316,12 +427,12 @@ PHP_FUNCTION(bcdiv)
316427

317428
bc_init_num(&result);
318429

319-
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
430+
if (php_str2num(&first, left) == FAILURE) {
320431
zend_argument_value_error(1, "is not well-formed");
321432
goto cleanup;
322433
}
323434

324-
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
435+
if (php_str2num(&second, right) == FAILURE) {
325436
zend_argument_value_error(2, "is not well-formed");
326437
goto cleanup;
327438
}
@@ -368,12 +479,12 @@ PHP_FUNCTION(bcmod)
368479

369480
bc_init_num(&result);
370481

371-
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
482+
if (php_str2num(&first, left) == FAILURE) {
372483
zend_argument_value_error(1, "is not well-formed");
373484
goto cleanup;
374485
}
375486

376-
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
487+
if (php_str2num(&second, right) == FAILURE) {
377488
zend_argument_value_error(2, "is not well-formed");
378489
goto cleanup;
379490
}
@@ -421,17 +532,17 @@ PHP_FUNCTION(bcpowmod)
421532

422533
bc_init_num(&result);
423534

424-
if (php_str2num(&bc_base, ZSTR_VAL(base_str)) == FAILURE) {
535+
if (php_str2num(&bc_base, base_str) == FAILURE) {
425536
zend_argument_value_error(1, "is not well-formed");
426537
goto cleanup;
427538
}
428539

429-
if (php_str2num(&bc_expo, ZSTR_VAL(exponent_str)) == FAILURE) {
540+
if (php_str2num(&bc_expo, exponent_str) == FAILURE) {
430541
zend_argument_value_error(2, "is not well-formed");
431542
goto cleanup;
432543
}
433544

434-
if (php_str2num(&bc_modulus, ZSTR_VAL(modulus_str)) == FAILURE) {
545+
if (php_str2num(&bc_modulus, modulus_str) == FAILURE) {
435546
zend_argument_value_error(3, "is not well-formed");
436547
goto cleanup;
437548
}
@@ -495,12 +606,12 @@ PHP_FUNCTION(bcpow)
495606

496607
bc_init_num(&result);
497608

498-
if (php_str2num(&first, ZSTR_VAL(base_str)) == FAILURE) {
609+
if (php_str2num(&first, base_str) == FAILURE) {
499610
zend_argument_value_error(1, "is not well-formed");
500611
goto cleanup;
501612
}
502613

503-
if (php_str2num(&bc_exponent, ZSTR_VAL(exponent_str)) == FAILURE) {
614+
if (php_str2num(&bc_exponent, exponent_str) == FAILURE) {
504615
zend_argument_value_error(2, "is not well-formed");
505616
goto cleanup;
506617
}
@@ -552,7 +663,7 @@ PHP_FUNCTION(bcsqrt)
552663
scale = (int) scale_param;
553664
}
554665

555-
if (php_str2num(&result, ZSTR_VAL(left)) == FAILURE) {
666+
if (php_str2num(&result, left) == FAILURE) {
556667
zend_argument_value_error(1, "is not well-formed");
557668
goto cleanup;
558669
}
@@ -625,7 +736,7 @@ static void bcfloor_or_bcceil(INTERNAL_FUNCTION_PARAMETERS, bool is_floor)
625736

626737
bc_init_num(&result);
627738

628-
if (php_str2num(&num, ZSTR_VAL(numstr)) == FAILURE) {
739+
if (php_str2num(&num, numstr) == FAILURE) {
629740
zend_argument_value_error(1, "is not well-formed");
630741
goto cleanup;
631742
}
@@ -686,7 +797,7 @@ PHP_FUNCTION(bcround)
686797

687798
bc_init_num(&result);
688799

689-
if (php_str2num(&num, ZSTR_VAL(numstr)) == FAILURE) {
800+
if (php_str2num(&num, numstr) == FAILURE) {
690801
zend_argument_value_error(1, "is not well-formed");
691802
goto cleanup;
692803
}

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)