32
32
ZEND_DECLARE_MODULE_GLOBALS (bcmath )
33
33
static PHP_GINIT_FUNCTION (bcmath );
34
34
static PHP_GSHUTDOWN_FUNCTION (bcmath );
35
+ static PHP_RINIT_FUNCTION (bcmath );
36
+ static PHP_RSHUTDOWN_FUNCTION (bcmath );
35
37
static PHP_MINIT_FUNCTION (bcmath );
36
38
static PHP_MSHUTDOWN_FUNCTION (bcmath );
37
39
static PHP_MINFO_FUNCTION (bcmath );
@@ -42,8 +44,8 @@ zend_module_entry bcmath_module_entry = {
42
44
ext_functions ,
43
45
PHP_MINIT (bcmath ),
44
46
PHP_MSHUTDOWN (bcmath ),
45
- NULL ,
46
- NULL ,
47
+ PHP_RINIT ( bcmath ) ,
48
+ PHP_RSHUTDOWN ( bcmath ) ,
47
49
PHP_MINFO (bcmath ),
48
50
PHP_BCMATH_VERSION ,
49
51
PHP_MODULE_GLOBALS (bcmath ),
@@ -82,6 +84,93 @@ PHP_INI_BEGIN()
82
84
PHP_INI_END ()
83
85
/* }}} */
84
86
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
+
85
174
/* {{{ PHP_GINIT_FUNCTION */
86
175
static PHP_GINIT_FUNCTION (bcmath )
87
176
{
@@ -102,6 +191,18 @@ static PHP_GSHUTDOWN_FUNCTION(bcmath)
102
191
}
103
192
/* }}} */
104
193
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
+
105
206
/* {{{ PHP_MINIT_FUNCTION */
106
207
PHP_MINIT_FUNCTION (bcmath )
107
208
{
@@ -132,12 +233,22 @@ PHP_MINFO_FUNCTION(bcmath)
132
233
133
234
/* {{{ php_str2num
134
235
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 )
136
237
{
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)) {
138
247
return FAILURE ;
139
248
}
140
249
250
+ bcmath_lru_add (cache , str , bc_copy_num (* num ));
251
+
141
252
return SUCCESS ;
142
253
}
143
254
/* }}} */
@@ -169,12 +280,12 @@ PHP_FUNCTION(bcadd)
169
280
170
281
bc_init_num (& result );
171
282
172
- if (php_str2num (& first , ZSTR_VAL ( left ) ) == FAILURE ) {
283
+ if (php_str2num (& first , left ) == FAILURE ) {
173
284
zend_argument_value_error (1 , "is not well-formed" );
174
285
goto cleanup ;
175
286
}
176
287
177
- if (php_str2num (& second , ZSTR_VAL ( right ) ) == FAILURE ) {
288
+ if (php_str2num (& second , right ) == FAILURE ) {
178
289
zend_argument_value_error (2 , "is not well-formed" );
179
290
goto cleanup ;
180
291
}
@@ -218,12 +329,12 @@ PHP_FUNCTION(bcsub)
218
329
219
330
bc_init_num (& result );
220
331
221
- if (php_str2num (& first , ZSTR_VAL ( left ) ) == FAILURE ) {
332
+ if (php_str2num (& first , left ) == FAILURE ) {
222
333
zend_argument_value_error (1 , "is not well-formed" );
223
334
goto cleanup ;
224
335
}
225
336
226
- if (php_str2num (& second , ZSTR_VAL ( right ) ) == FAILURE ) {
337
+ if (php_str2num (& second , right ) == FAILURE ) {
227
338
zend_argument_value_error (2 , "is not well-formed" );
228
339
goto cleanup ;
229
340
}
@@ -267,12 +378,12 @@ PHP_FUNCTION(bcmul)
267
378
268
379
bc_init_num (& result );
269
380
270
- if (php_str2num (& first , ZSTR_VAL ( left ) ) == FAILURE ) {
381
+ if (php_str2num (& first , left ) == FAILURE ) {
271
382
zend_argument_value_error (1 , "is not well-formed" );
272
383
goto cleanup ;
273
384
}
274
385
275
- if (php_str2num (& second , ZSTR_VAL ( right ) ) == FAILURE ) {
386
+ if (php_str2num (& second , right ) == FAILURE ) {
276
387
zend_argument_value_error (2 , "is not well-formed" );
277
388
goto cleanup ;
278
389
}
@@ -316,12 +427,12 @@ PHP_FUNCTION(bcdiv)
316
427
317
428
bc_init_num (& result );
318
429
319
- if (php_str2num (& first , ZSTR_VAL ( left ) ) == FAILURE ) {
430
+ if (php_str2num (& first , left ) == FAILURE ) {
320
431
zend_argument_value_error (1 , "is not well-formed" );
321
432
goto cleanup ;
322
433
}
323
434
324
- if (php_str2num (& second , ZSTR_VAL ( right ) ) == FAILURE ) {
435
+ if (php_str2num (& second , right ) == FAILURE ) {
325
436
zend_argument_value_error (2 , "is not well-formed" );
326
437
goto cleanup ;
327
438
}
@@ -368,12 +479,12 @@ PHP_FUNCTION(bcmod)
368
479
369
480
bc_init_num (& result );
370
481
371
- if (php_str2num (& first , ZSTR_VAL ( left ) ) == FAILURE ) {
482
+ if (php_str2num (& first , left ) == FAILURE ) {
372
483
zend_argument_value_error (1 , "is not well-formed" );
373
484
goto cleanup ;
374
485
}
375
486
376
- if (php_str2num (& second , ZSTR_VAL ( right ) ) == FAILURE ) {
487
+ if (php_str2num (& second , right ) == FAILURE ) {
377
488
zend_argument_value_error (2 , "is not well-formed" );
378
489
goto cleanup ;
379
490
}
@@ -421,17 +532,17 @@ PHP_FUNCTION(bcpowmod)
421
532
422
533
bc_init_num (& result );
423
534
424
- if (php_str2num (& bc_base , ZSTR_VAL ( base_str ) ) == FAILURE ) {
535
+ if (php_str2num (& bc_base , base_str ) == FAILURE ) {
425
536
zend_argument_value_error (1 , "is not well-formed" );
426
537
goto cleanup ;
427
538
}
428
539
429
- if (php_str2num (& bc_expo , ZSTR_VAL ( exponent_str ) ) == FAILURE ) {
540
+ if (php_str2num (& bc_expo , exponent_str ) == FAILURE ) {
430
541
zend_argument_value_error (2 , "is not well-formed" );
431
542
goto cleanup ;
432
543
}
433
544
434
- if (php_str2num (& bc_modulus , ZSTR_VAL ( modulus_str ) ) == FAILURE ) {
545
+ if (php_str2num (& bc_modulus , modulus_str ) == FAILURE ) {
435
546
zend_argument_value_error (3 , "is not well-formed" );
436
547
goto cleanup ;
437
548
}
@@ -495,12 +606,12 @@ PHP_FUNCTION(bcpow)
495
606
496
607
bc_init_num (& result );
497
608
498
- if (php_str2num (& first , ZSTR_VAL ( base_str ) ) == FAILURE ) {
609
+ if (php_str2num (& first , base_str ) == FAILURE ) {
499
610
zend_argument_value_error (1 , "is not well-formed" );
500
611
goto cleanup ;
501
612
}
502
613
503
- if (php_str2num (& bc_exponent , ZSTR_VAL ( exponent_str ) ) == FAILURE ) {
614
+ if (php_str2num (& bc_exponent , exponent_str ) == FAILURE ) {
504
615
zend_argument_value_error (2 , "is not well-formed" );
505
616
goto cleanup ;
506
617
}
@@ -552,7 +663,7 @@ PHP_FUNCTION(bcsqrt)
552
663
scale = (int ) scale_param ;
553
664
}
554
665
555
- if (php_str2num (& result , ZSTR_VAL ( left ) ) == FAILURE ) {
666
+ if (php_str2num (& result , left ) == FAILURE ) {
556
667
zend_argument_value_error (1 , "is not well-formed" );
557
668
goto cleanup ;
558
669
}
@@ -625,7 +736,7 @@ static void bcfloor_or_bcceil(INTERNAL_FUNCTION_PARAMETERS, bool is_floor)
625
736
626
737
bc_init_num (& result );
627
738
628
- if (php_str2num (& num , ZSTR_VAL ( numstr ) ) == FAILURE ) {
739
+ if (php_str2num (& num , numstr ) == FAILURE ) {
629
740
zend_argument_value_error (1 , "is not well-formed" );
630
741
goto cleanup ;
631
742
}
@@ -686,7 +797,7 @@ PHP_FUNCTION(bcround)
686
797
687
798
bc_init_num (& result );
688
799
689
- if (php_str2num (& num , ZSTR_VAL ( numstr ) ) == FAILURE ) {
800
+ if (php_str2num (& num , numstr ) == FAILURE ) {
690
801
zend_argument_value_error (1 , "is not well-formed" );
691
802
goto cleanup ;
692
803
}
0 commit comments