Skip to content

Commit 4bde620

Browse files
committed
SplSequenceGenerator
1 parent d4d726b commit 4bde620

File tree

9 files changed

+531
-125
lines changed

9 files changed

+531
-125
lines changed

a.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
echo "Max\n";
3+
var_dump(SplSequenceGenerator::MAX);
4+
var_dump(mt_getrandmax());
5+
6+
$obj = new SplSequenceGenerator(20);
7+
mt_srand(20);
8+
9+
for ($i = 0; $i < 1000; $i++)
10+
{
11+
echo "Itr $i\n";
12+
var_dump($obj->getNextNumber(0, 1000));
13+
var_dump(mt_rand(0, 1000));
14+
}
15+
$b = clone $obj;
16+
$c = unserialize(serialize($b));
17+
echo "End\n";
18+
19+
var_dump($obj->getNextNumber(0, 1000));
20+
var_dump($b->getNextNumber(0, 1000));
21+
var_dump($c->getNextNumber(0, 1000));
22+
var_dump(mt_rand(0, 1000));

ext/spl/config.m4

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@ int main(int argc, char **argv) {
2222
CPPFLAGS=$old_CPPFLAGS
2323
AC_DEFINE_UNQUOTED(HAVE_PACKED_OBJECT_VALUE, $ac_result, [Whether struct _zend_object_value is packed])
2424
AC_DEFINE(HAVE_SPL, 1, [Whether you want SPL (Standard PHP Library) support])
25-
PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c spl_fixedarray.c, no)
26-
PHP_INSTALL_HEADERS([ext/spl], [php_spl.h spl_array.h spl_directory.h spl_engine.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_dllist.h spl_heap.h spl_fixedarray.h])
25+
PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c spl_fixedarray.c spl_sequence.c, no)
26+
PHP_INSTALL_HEADERS([ext/spl], [php_spl.h spl_array.h spl_directory.h spl_engine.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_dllist.h spl_heap.h spl_fixedarray.h spl_sequence.h])
2727
PHP_ADD_EXTENSION_DEP(spl, pcre, true)

ext/spl/php_spl.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,7 @@ PHP_MINIT_FUNCTION(spl)
948948
PHP_MINIT(spl_heap)(INIT_FUNC_ARGS_PASSTHRU);
949949
PHP_MINIT(spl_fixedarray)(INIT_FUNC_ARGS_PASSTHRU);
950950
PHP_MINIT(spl_observer)(INIT_FUNC_ARGS_PASSTHRU);
951+
PHP_MINIT(spl_sequence)(INIT_FUNC_ARGS_PASSTHRU);
951952

952953
return SUCCESS;
953954
}

ext/spl/spl_sequence.c

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| PHP Version 5 |
4+
+----------------------------------------------------------------------+
5+
| Copyright (c) 1997-2014 The PHP Group |
6+
+----------------------------------------------------------------------+
7+
| This source file is subject to version 3.01 of the PHP license, |
8+
| that is bundled with this package in the file LICENSE, and is |
9+
| available through the world-wide-web at the following url: |
10+
| http://www.php.net/license/3_01.txt |
11+
| If you did not receive a copy of the PHP license and are unable to |
12+
| obtain it through the world-wide-web, please send a note to |
13+
| [email protected] so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
| Authors: Rouven Weßling <[email protected]> |
16+
+----------------------------------------------------------------------+
17+
*/
18+
19+
20+
#ifdef HAVE_CONFIG_H
21+
# include "config.h"
22+
#endif
23+
24+
#include "php.h"
25+
#include "zend_interfaces.h"
26+
#include "zend_exceptions.h"
27+
#include "ext/standard/php_rand.h"
28+
#include "ext/standard/php_var.h"
29+
#include "ext/standard/php_lcg.h"
30+
#include "ext/standard/php_smart_str.h"
31+
#include "ext/standard/mersenne.h"
32+
33+
#include "php_spl.h"
34+
#include "spl_iterators.h"
35+
#include "spl_exceptions.h"
36+
#include "spl_functions.h"
37+
38+
#define STATE_SIZE MT_N * (4 / sizeof(char))
39+
40+
PHPAPI zend_class_entry *spl_ce_SplSequenceGenerator;
41+
42+
ZEND_BEGIN_ARG_INFO(arginfo_SplSequenceGenerator___construct, 0)
43+
ZEND_ARG_INFO(0, seed)
44+
ZEND_END_ARG_INFO();
45+
46+
ZEND_BEGIN_ARG_INFO_EX(arginfo_SplSequenceGenerator_getNextNumber, 0, 0, 0)
47+
ZEND_ARG_INFO(0, min)
48+
ZEND_ARG_INFO(0, max)
49+
ZEND_END_ARG_INFO();
50+
51+
ZEND_BEGIN_ARG_INFO(arginfo_SplSequenceGenerator_serialize, 0)
52+
ZEND_ARG_INFO(0, seed)
53+
ZEND_END_ARG_INFO();
54+
55+
ZEND_BEGIN_ARG_INFO(arginfo_SplSequenceGenerator_unserialize, 0)
56+
ZEND_ARG_INFO(0, serialized)
57+
ZEND_END_ARG_INFO();
58+
59+
typedef struct _spl_sequencegenerator_object { /* {{{ */
60+
zend_object std;
61+
php_uint32 state[MT_N+1]; /* state vector + 1 extra to not violate ANSI C */
62+
int left; /* can access this many values before reloading */
63+
} spl_sequencegenerator_object;
64+
/* }}} */
65+
66+
PHPAPI zend_object_handlers spl_handler_SplSequenceGenerator;
67+
68+
SPL_METHOD(SplSequenceGenerator, __construct)
69+
{
70+
php_uint32 seed = 0;
71+
zval *object;
72+
spl_sequencegenerator_object *intern;
73+
74+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &seed) == FAILURE) {
75+
return;
76+
}
77+
78+
object = getThis();
79+
intern = zend_object_store_get_object(object TSRMLS_CC);
80+
81+
if (ZEND_NUM_ARGS() == 0) {
82+
seed = GENERATE_SEED();
83+
}
84+
85+
php_mt_initialize(seed, intern->state);
86+
php_mt_reload(&intern->state, &intern->left TSRMLS_CC);
87+
}
88+
89+
SPL_METHOD(SplSequenceGenerator, serialize)
90+
{
91+
spl_sequencegenerator_object *intern;
92+
smart_str buf = {0};
93+
php_serialize_data_t var_hash;
94+
zval zv, *zv_ptr = &zv;
95+
96+
if (zend_parse_parameters_none() == FAILURE) {
97+
return;
98+
}
99+
100+
intern = zend_object_store_get_object(getThis() TSRMLS_CC);
101+
if (!intern->state && !intern->left) {
102+
return;
103+
}
104+
105+
PHP_VAR_SERIALIZE_INIT(var_hash);
106+
107+
INIT_PZVAL(zv_ptr);
108+
109+
ZVAL_LONG(zv_ptr, intern->left);
110+
php_var_serialize(&buf, &zv_ptr, &var_hash TSRMLS_CC);
111+
112+
ZVAL_STRINGL(zv_ptr, (char *) intern->state, STATE_SIZE, 0);
113+
php_var_serialize(&buf, &zv_ptr, &var_hash TSRMLS_CC);
114+
115+
Z_ARRVAL_P(zv_ptr) = zend_std_get_properties(getThis() TSRMLS_CC);
116+
Z_TYPE_P(zv_ptr) = IS_ARRAY;
117+
php_var_serialize(&buf, &zv_ptr, &var_hash TSRMLS_CC);
118+
119+
PHP_VAR_SERIALIZE_DESTROY(var_hash);
120+
121+
if (buf.c) {
122+
RETURN_STRINGL(buf.c, buf.len, 0);
123+
}
124+
}
125+
126+
SPL_METHOD(SplSequenceGenerator, unserialize)
127+
{
128+
spl_sequencegenerator_object *intern;
129+
char *buf;
130+
int buf_len;
131+
php_unserialize_data_t var_hash;
132+
const unsigned char *p, *max;
133+
zval zv, *zv_ptr = &zv;
134+
135+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
136+
return;
137+
}
138+
139+
if (buf_len == 0) {
140+
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Empty serialized string cannot be empty");
141+
return;
142+
}
143+
144+
intern = zend_object_store_get_object(getThis() TSRMLS_CC);
145+
146+
if (intern->state && intern->left) {
147+
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Cannot call unserialize() on an already constructed object");
148+
return;
149+
}
150+
151+
PHP_VAR_UNSERIALIZE_INIT(var_hash);
152+
153+
p = (unsigned char *) buf;
154+
max = (unsigned char *) buf + buf_len;
155+
156+
INIT_ZVAL(zv);
157+
if (!php_var_unserialize(&zv_ptr, &p, max, &var_hash TSRMLS_CC)
158+
|| Z_TYPE_P(zv_ptr) != IS_LONG) {
159+
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
160+
goto exit;
161+
}
162+
163+
intern->left = Z_LVAL_P(zv_ptr);
164+
165+
INIT_ZVAL(zv);
166+
if (!php_var_unserialize(&zv_ptr, &p, max, &var_hash TSRMLS_CC)
167+
|| Z_TYPE_P(zv_ptr) != IS_STRING || Z_STRLEN_P(zv_ptr) == 0) {
168+
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
169+
goto exit;
170+
}
171+
if (STATE_SIZE != Z_STRLEN_P(zv_ptr)) {
172+
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Expected state size %d, got %d", STATE_SIZE, Z_STRLEN_P(zv_ptr));
173+
}
174+
175+
memcpy(intern->state, Z_STRVAL_P(zv_ptr), Z_STRLEN_P(zv_ptr));
176+
177+
INIT_ZVAL(zv);
178+
if (!php_var_unserialize(&zv_ptr, &p, max, &var_hash TSRMLS_CC)
179+
|| Z_TYPE_P(zv_ptr) != IS_ARRAY) {
180+
zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
181+
goto exit;
182+
}
183+
184+
if (zend_hash_num_elements(Z_ARRVAL_P(zv_ptr)) != 0) {
185+
zend_hash_copy(
186+
zend_std_get_properties(getThis() TSRMLS_CC), Z_ARRVAL_P(zv_ptr),
187+
(copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)
188+
);
189+
}
190+
191+
exit:
192+
zval_dtor(zv_ptr);
193+
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
194+
return;
195+
}
196+
197+
SPL_METHOD(SplSequenceGenerator, getNextNumber)
198+
{
199+
zval *object;
200+
spl_sequencegenerator_object *intern;
201+
202+
object = getThis();
203+
intern = zend_object_store_get_object(object TSRMLS_CC);
204+
205+
long min;
206+
long max;
207+
long number;
208+
int argc = ZEND_NUM_ARGS();
209+
210+
if (argc != 0) {
211+
if (zend_parse_parameters(argc TSRMLS_CC, "ll", &min, &max) == FAILURE) {
212+
return;
213+
} else if (max < min) {
214+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "max(%ld) is smaller than min(%ld)", max, min);
215+
RETURN_FALSE;
216+
}
217+
}
218+
219+
number = (long) (php_mt_get_number(&intern->state, &intern->left TSRMLS_CC) >> 1);
220+
if (argc == 2) {
221+
RAND_RANGE(number, min, max, PHP_MT_RAND_MAX);
222+
}
223+
224+
RETURN_LONG(number);
225+
}
226+
227+
static const zend_function_entry spl_funcs_SplSequenceGenerator[] = {
228+
SPL_ME(SplSequenceGenerator, __construct, arginfo_SplSequenceGenerator___construct, ZEND_ACC_PUBLIC)
229+
SPL_ME(SplSequenceGenerator, serialize, arginfo_SplSequenceGenerator_serialize, ZEND_ACC_PUBLIC)
230+
SPL_ME(SplSequenceGenerator, unserialize, arginfo_SplSequenceGenerator_unserialize, ZEND_ACC_PUBLIC)
231+
SPL_ME(SplSequenceGenerator, getNextNumber, arginfo_SplSequenceGenerator_getNextNumber, ZEND_ACC_PUBLIC)
232+
PHP_FE_END
233+
};
234+
235+
static void spl_sequencegenerator_object_free_storage(spl_sequencegenerator_object *intern TSRMLS_DC)
236+
{
237+
zend_object_std_dtor(&intern->std TSRMLS_CC);
238+
efree(intern);
239+
}
240+
/* }}} */
241+
242+
static zend_object_value spl_sequencegenerator_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
243+
{
244+
zend_object_value retval;
245+
246+
spl_sequencegenerator_object *intern = ecalloc(1, sizeof(spl_sequencegenerator_object));
247+
248+
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
249+
object_properties_init(&intern->std, class_type);
250+
251+
retval.handle = zend_objects_store_put(
252+
intern,
253+
(zend_objects_store_dtor_t) zend_objects_destroy_object,
254+
(zend_objects_free_object_storage_t) spl_sequencegenerator_object_free_storage,
255+
NULL TSRMLS_CC
256+
);
257+
258+
retval.handlers = &spl_handler_SplSequenceGenerator;
259+
260+
return retval;
261+
}
262+
/* }}} */
263+
264+
static zend_object_value spl_sequencegenerator_object_clone(zval *object TSRMLS_DC)
265+
{
266+
spl_sequencegenerator_object *old_object = zend_object_store_get_object(object TSRMLS_CC);
267+
268+
zend_object_value new_object_val = spl_sequencegenerator_new(Z_OBJCE_P(object) TSRMLS_CC);
269+
270+
spl_sequencegenerator_object *new_object = zend_object_store_get_object_by_handle(
271+
new_object_val.handle TSRMLS_CC
272+
);
273+
274+
zend_objects_clone_members(
275+
&new_object->std, new_object_val,
276+
&old_object->std, Z_OBJ_HANDLE_P(object) TSRMLS_CC
277+
);
278+
279+
memcpy(new_object->state, old_object->state, sizeof(old_object->state));
280+
new_object->left = old_object->left;
281+
282+
return new_object_val;
283+
}
284+
285+
/* {{{ PHP_MINIT_FUNCTION(spl_sequence) */
286+
PHP_MINIT_FUNCTION(spl_sequence)
287+
{
288+
REGISTER_SPL_STD_CLASS_EX(SplSequenceGenerator, spl_sequencegenerator_new, spl_funcs_SplSequenceGenerator);
289+
REGISTER_SPL_IMPLEMENTS(SplSequenceGenerator, Serializable);
290+
memcpy(&spl_handler_SplSequenceGenerator, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
291+
292+
spl_handler_SplSequenceGenerator.clone_obj = spl_sequencegenerator_object_clone;
293+
294+
REGISTER_SPL_CLASS_CONST_LONG(SplSequenceGenerator, "MAX", PHP_MT_RAND_MAX);
295+
296+
return SUCCESS;
297+
}
298+
/* }}} */
299+
300+
/*
301+
* Local variables:
302+
* tab-width: 4
303+
* c-basic-offset: 4
304+
* End:
305+
* vim600: fdm=marker
306+
* vim: noet sw=4 ts=4
307+
*/

ext/spl/spl_sequence.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| PHP Version 5 |
4+
+----------------------------------------------------------------------+
5+
| Copyright (c) 1997-2014 The PHP Group |
6+
+----------------------------------------------------------------------+
7+
| This source file is subject to version 3.01 of the PHP license, |
8+
| that is bundled with this package in the file LICENSE, and is |
9+
| available through the world-wide-web at the following url: |
10+
| http://www.php.net/license/3_01.txt |
11+
| If you did not receive a copy of the PHP license and are unable to |
12+
| obtain it through the world-wide-web, please send a note to |
13+
| [email protected] so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
| Authors: Rouven Weßling <[email protected]> |
16+
+----------------------------------------------------------------------+
17+
*/
18+
19+
#ifndef SPL_SEQUENCE_H
20+
#define SPL_SEQUENCE_H
21+
22+
#include "php.h"
23+
#include "php_spl.h"
24+
#include "spl_sequence.h"
25+
26+
extern PHPAPI zend_class_entry *spl_ce_SplSequenceGenerator;
27+
28+
PHP_MINIT_FUNCTION(spl_sequence);
29+
30+
#endif /* SPL_SEQUENCE_H */
31+
32+
/*
33+
* Local Variables:
34+
* c-basic-offset: 4
35+
* tab-width: 4
36+
* End:
37+
* vim600: fdm=marker
38+
* vim: noet sw=4 ts=4
39+
*/

ext/standard/basic_functions.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3442,7 +3442,6 @@ static void basic_globals_ctor(php_basic_globals *basic_globals_p TSRMLS_DC) /*
34423442
BG(rand_is_seeded) = 0;
34433443
BG(mt_rand_is_seeded) = 0;
34443444
BG(umask) = -1;
3445-
BG(next) = NULL;
34463445
BG(left) = -1;
34473446
BG(user_tick_functions) = NULL;
34483447
BG(user_filter_map) = NULL;

0 commit comments

Comments
 (0)