Skip to content

Commit 77daa34

Browse files
committed
BreakIterator::getPartsIterator: new optional arg
Can take one of: * IntlPartsIterator::KEY_SEQUENTIAL (keys are 0, 1, ...) * IntlPartsIterator::KEY_LEFT (keys are left boundaries) * IntlPartsIterator::KEY_LEFT (keys are right boundaries) The default is IntlPartsIterator::KEY_SEQUENTIAL (the previous behavior).
1 parent 0a7ae87 commit 77daa34

File tree

6 files changed

+152
-7
lines changed

6 files changed

+152
-7
lines changed

ext/intl/breakiterator/breakiterator_class.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,10 @@ ZEND_BEGIN_ARG_INFO_EX(ainfo_biter_get_locale, 0, 0, 1)
264264
ZEND_ARG_INFO(0, "locale_type")
265265
ZEND_END_ARG_INFO()
266266

267+
ZEND_BEGIN_ARG_INFO_EX(ainfo_biter_getPartsIterator, 0, 0, 0)
268+
ZEND_ARG_INFO(0, "key_type")
269+
ZEND_END_ARG_INFO()
270+
267271
ZEND_BEGIN_ARG_INFO_EX(ainfo_rbbi___construct, 0, 0, 1)
268272
ZEND_ARG_INFO(0, "rules")
269273
ZEND_ARG_INFO(0, "areCompiled")
@@ -293,7 +297,7 @@ static const zend_function_entry BreakIterator_class_functions[] = {
293297
PHP_ME_MAPPING(preceding, breakiter_preceding, ainfo_biter_offset, ZEND_ACC_PUBLIC)
294298
PHP_ME_MAPPING(isBoundary, breakiter_is_boundary, ainfo_biter_offset, ZEND_ACC_PUBLIC)
295299
PHP_ME_MAPPING(getLocale, breakiter_get_locale, ainfo_biter_void, ZEND_ACC_PUBLIC)
296-
PHP_ME_MAPPING(getPartsIterator, breakiter_get_parts_iterator, ainfo_biter_void, ZEND_ACC_PUBLIC)
300+
PHP_ME_MAPPING(getPartsIterator, breakiter_get_parts_iterator, ainfo_biter_getPartsIterator, ZEND_ACC_PUBLIC)
297301

298302
PHP_ME_MAPPING(getErrorCode, breakiter_get_error_code, ainfo_biter_void, ZEND_ACC_PUBLIC)
299303
PHP_ME_MAPPING(getErrorMessage, breakiter_get_error_message, ainfo_biter_void, ZEND_ACC_PUBLIC)

ext/intl/breakiterator/breakiterator_iterators.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ U_CFUNC zend_object_iterator *_breakiterator_get_iterator(
130130

131131
typedef struct zoi_break_iter_parts {
132132
zoi_with_current zoi_cur;
133+
parts_iter_key_type key_type;
133134
BreakIterator_object *bio; /* so we don't have to fetch it all the time */
134135
} zoi_break_iter_parts;
135136

@@ -138,6 +139,16 @@ static void _breakiterator_parts_destroy_it(zend_object_iterator *iter TSRMLS_DC
138139
zval_ptr_dtor(reinterpret_cast<zval**>(&iter->data));
139140
}
140141

142+
static int _breakiterator_parts_get_current_key(zend_object_iterator *iter,
143+
char **str_key,
144+
uint *str_key_len,
145+
ulong *int_key TSRMLS_DC)
146+
{
147+
/* the actual work is done in move_forward and rewind */
148+
*int_key = iter->index;
149+
return HASH_KEY_IS_LONG;
150+
}
151+
141152
static void _breakiterator_parts_move_forward(zend_object_iterator *iter TSRMLS_DC)
142153
{
143154
zoi_break_iter_parts *zoi_bit = (zoi_break_iter_parts*)iter;
@@ -157,6 +168,14 @@ static void _breakiterator_parts_move_forward(zend_object_iterator *iter TSRMLS_
157168
return;
158169
}
159170

171+
if (zoi_bit->key_type == PARTS_ITERATOR_KEY_LEFT) {
172+
iter->index = cur;
173+
} else if (zoi_bit->key_type == PARTS_ITERATOR_KEY_RIGHT) {
174+
iter->index = next;
175+
}
176+
/* else zoi_bit->key_type == PARTS_ITERATOR_KEY_SEQUENTIAL
177+
* No need to do anything, the engine increments ->index */
178+
160179
const char *s = Z_STRVAL_P(bio->text);
161180
int32_t slen = Z_STRLEN_P(bio->text),
162181
len;
@@ -194,14 +213,15 @@ static zend_object_iterator_funcs breakiterator_parts_it_funcs = {
194213
zoi_with_current_dtor,
195214
zoi_with_current_valid,
196215
zoi_with_current_get_current_data,
197-
NULL,
216+
_breakiterator_parts_get_current_key,
198217
_breakiterator_parts_move_forward,
199218
_breakiterator_parts_rewind,
200219
zoi_with_current_invalidate_current
201220
};
202221

203222
void IntlIterator_from_BreakIterator_parts(zval *break_iter_zv,
204-
zval *object TSRMLS_DC)
223+
zval *object,
224+
parts_iter_key_type key_type TSRMLS_DC)
205225
{
206226
IntlIterator_object *ii;
207227

@@ -221,6 +241,7 @@ void IntlIterator_from_BreakIterator_parts(zval *break_iter_zv,
221241
((zoi_break_iter_parts*)ii->iterator)->bio = (BreakIterator_object*)
222242
zend_object_store_get_object(break_iter_zv TSRMLS_CC);
223243
assert(((zoi_break_iter_parts*)ii->iterator)->bio->biter != NULL);
244+
((zoi_break_iter_parts*)ii->iterator)->key_type = key_type;
224245
}
225246

226247
U_CFUNC zend_object_value IntlPartsIterator_object_create(zend_class_entry *ce TSRMLS_DC)
@@ -312,4 +333,14 @@ U_CFUNC void breakiterator_register_IntlPartsIterator_class(TSRMLS_D)
312333
memcpy(&IntlPartsIterator_handlers, &IntlIterator_handlers,
313334
sizeof IntlPartsIterator_handlers);
314335
IntlPartsIterator_handlers.get_method = IntlPartsIterator_get_method;
336+
337+
#define PARTSITER_DECL_LONG_CONST(name) \
338+
zend_declare_class_constant_long(IntlPartsIterator_ce_ptr, #name, \
339+
sizeof(#name) - 1, PARTS_ITERATOR_ ## name TSRMLS_CC)
340+
341+
PARTSITER_DECL_LONG_CONST(KEY_SEQUENTIAL);
342+
PARTSITER_DECL_LONG_CONST(KEY_LEFT);
343+
PARTSITER_DECL_LONG_CONST(KEY_RIGHT);
344+
345+
#undef PARTSITER_DECL_LONG_CONST
315346
}

ext/intl/breakiterator/breakiterator_iterators.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,16 @@ U_CDECL_BEGIN
2323
#include <php.h>
2424
U_CDECL_END
2525

26+
typedef enum {
27+
PARTS_ITERATOR_KEY_SEQUENTIAL,
28+
PARTS_ITERATOR_KEY_LEFT,
29+
PARTS_ITERATOR_KEY_RIGHT,
30+
} parts_iter_key_type;
31+
2632
#ifdef __cplusplus
2733
void IntlIterator_from_BreakIterator_parts(zval *break_iter_zv,
28-
zval *object TSRMLS_DC);
34+
zval *object,
35+
parts_iter_key_type key_type TSRMLS_DC);
2936
#endif
3037

3138
U_CFUNC zend_object_iterator *_breakiterator_get_iterator(

ext/intl/breakiterator/breakiterator_methods.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -384,18 +384,28 @@ U_CFUNC PHP_FUNCTION(breakiter_get_locale)
384384

385385
U_CFUNC PHP_FUNCTION(breakiter_get_parts_iterator)
386386
{
387+
long key_type = 0;
387388
BREAKITER_METHOD_INIT_VARS;
388389
object = getThis();
389390

390-
if (zend_parse_parameters_none() == FAILURE) {
391+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &key_type) == FAILURE) {
392+
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
393+
"breakiter_get_parts_iterator: bad arguments", 0 TSRMLS_CC);
394+
RETURN_FALSE;
395+
}
396+
397+
if (key_type != PARTS_ITERATOR_KEY_SEQUENTIAL
398+
&& key_type != PARTS_ITERATOR_KEY_LEFT
399+
&& key_type != PARTS_ITERATOR_KEY_RIGHT) {
391400
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
392-
"breakiter_get_parts_iterator: bad arguments", 0 TSRMLS_CC);
401+
"breakiter_get_parts_iterator: bad key type", 0 TSRMLS_CC);
393402
RETURN_FALSE;
394403
}
395404

396405
BREAKITER_METHOD_FETCH_OBJECT;
397406

398-
IntlIterator_from_BreakIterator_parts(object, return_value TSRMLS_CC);
407+
IntlIterator_from_BreakIterator_parts(
408+
object, return_value, (parts_iter_key_type)key_type TSRMLS_CC);
399409
}
400410

401411
U_CFUNC PHP_FUNCTION(breakiter_get_error_code)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
IntlBreakIterator::getPartsIterator(): bad args
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('intl'))
6+
die('skip intl extension not enabled');
7+
--FILE--
8+
<?php
9+
ini_set("intl.error_level", E_WARNING);
10+
ini_set("intl.default_locale", "pt_PT");
11+
12+
$it = IntlBreakIterator::createWordInstance(NULL);
13+
var_dump($it->getPartsIterator(array()));
14+
var_dump($it->getPartsIterator(1, 2));
15+
var_dump($it->getPartsIterator(-1));
16+
17+
?>
18+
==DONE==
19+
--EXPECTF--
20+
21+
Warning: IntlBreakIterator::getPartsIterator() expects parameter 1 to be long, array given in %s on line %d
22+
23+
Warning: IntlBreakIterator::getPartsIterator(): breakiter_get_parts_iterator: bad arguments in %s on line %d
24+
bool(false)
25+
26+
Warning: IntlBreakIterator::getPartsIterator() expects at most 1 parameter, 2 given in %s on line %d
27+
28+
Warning: IntlBreakIterator::getPartsIterator(): breakiter_get_parts_iterator: bad arguments in %s on line %d
29+
bool(false)
30+
31+
Warning: IntlBreakIterator::getPartsIterator(): breakiter_get_parts_iterator: bad key type in %s on line %d
32+
bool(false)
33+
==DONE==
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
--TEST--
2+
IntlBreakIterator::getPartsIterator(): argument variations
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('intl'))
6+
die('skip intl extension not enabled');
7+
--FILE--
8+
<?php
9+
ini_set("intl.error_level", E_WARNING);
10+
ini_set("intl.default_locale", "pt_PT");
11+
12+
$text = 'foo bar tao';
13+
14+
$it = IntlBreakIterator::createWordInstance(NULL);
15+
$it->setText($text);
16+
17+
var_dump(iterator_to_array($it->getPartsIterator(IntlPartsIterator::KEY_SEQUENTIAL)));
18+
var_dump(iterator_to_array($it->getPartsIterator(IntlPartsIterator::KEY_LEFT)));
19+
var_dump(iterator_to_array($it->getPartsIterator(IntlPartsIterator::KEY_RIGHT)));
20+
21+
?>
22+
==DONE==
23+
--EXPECT--
24+
array(5) {
25+
[0]=>
26+
string(3) "foo"
27+
[1]=>
28+
string(1) " "
29+
[2]=>
30+
string(3) "bar"
31+
[3]=>
32+
string(1) " "
33+
[4]=>
34+
string(3) "tao"
35+
}
36+
array(5) {
37+
[0]=>
38+
string(3) "foo"
39+
[4]=>
40+
string(1) " "
41+
[5]=>
42+
string(3) "bar"
43+
[8]=>
44+
string(1) " "
45+
[9]=>
46+
string(3) "tao"
47+
}
48+
array(5) {
49+
[3]=>
50+
string(3) "foo"
51+
[5]=>
52+
string(1) " "
53+
[8]=>
54+
string(3) "bar"
55+
[9]=>
56+
string(1) " "
57+
[12]=>
58+
string(3) "tao"
59+
}
60+
==DONE==

0 commit comments

Comments
 (0)