Skip to content

Commit 3671e0b

Browse files
committed
Reimplement matches more efficiently
1 parent e14a6cb commit 3671e0b

File tree

1 file changed

+81
-30
lines changed

1 file changed

+81
-30
lines changed

ext/dom/parentnode/css_selectors.c

Lines changed: 81 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -61,51 +61,107 @@ lxb_status_t php_dom_query_selector_find_matches_callback(const xmlNode *node, l
6161
return LXB_STATUS_OK;
6262
}
6363

64-
static lxb_status_t php_dom_query_selector_common(
65-
zval *return_value,
66-
const xmlNode *root,
67-
zend_string *selectors_str,
68-
lxb_selectors_cb_f cb,
69-
void *ctx,
64+
static lxb_css_selector_list_t *php_dom_parse_selector(
65+
lxb_css_parser_t *parser,
66+
lxb_selectors_t *selectors,
67+
const zend_string *selectors_str,
7068
lxb_selectors_opt_t options
7169
)
7270
{
7371
lxb_status_t status;
7472

75-
lxb_css_parser_t parser;
76-
memset(&parser, 0, sizeof(lxb_css_parser_t));
77-
status = lxb_css_parser_init(&parser, NULL);
73+
memset(parser, 0, sizeof(lxb_css_parser_t));
74+
status = lxb_css_parser_init(parser, NULL);
7875
ZEND_ASSERT(status == LXB_STATUS_OK);
7976

80-
lxb_selectors_t selectors;
81-
memset(&selectors, 0, sizeof(lxb_selectors_t));
82-
status = lxb_selectors_init(&selectors);
77+
memset(selectors, 0, sizeof(lxb_selectors_t));
78+
status = lxb_selectors_init(selectors);
8379
ZEND_ASSERT(status == LXB_STATUS_OK);
84-
lxb_selectors_opt_set(&selectors, options);
80+
lxb_selectors_opt_set(selectors, options);
8581

86-
lxb_css_selector_list_t *list = lxb_css_selectors_parse(&parser, (const lxb_char_t *) ZSTR_VAL(selectors_str), ZSTR_LEN(selectors_str));
82+
lxb_css_selector_list_t *list = lxb_css_selectors_parse(parser, (const lxb_char_t *) ZSTR_VAL(selectors_str), ZSTR_LEN(selectors_str));
8783
if (UNEXPECTED(list == NULL)) {
88-
size_t nr_of_messages = lexbor_array_obj_length(&parser.log->messages);
84+
size_t nr_of_messages = lexbor_array_obj_length(&parser->log->messages);
8985
if (nr_of_messages > 0) {
90-
lxb_css_log_message_t *msg = lexbor_array_obj_get(&parser.log->messages, 0);
86+
lxb_css_log_message_t *msg = lexbor_array_obj_get(&parser->log->messages, 0);
9187
char *error;
9288
zend_spprintf(&error, 0, "Invalid selector (%.*s)", (int) msg->text.length, msg->text.data);
9389
php_dom_throw_error_with_message(SYNTAX_ERR, error, true);
9490
efree(error);
9591
} else {
9692
php_dom_throw_error_with_message(SYNTAX_ERR, "Invalid selector", true);
9793
}
94+
}
95+
96+
return list;
97+
}
98+
99+
static lxb_status_t php_dom_check_css_execution_status(lxb_status_t status)
100+
{
101+
if (UNEXPECTED(status != LXB_STATUS_OK && status != LXB_STATUS_STOP)) {
102+
zend_argument_value_error(1, "contains an unsupported selector");
103+
return status;
104+
}
105+
return LXB_STATUS_OK;
106+
}
107+
108+
static void php_dom_selector_cleanup(lxb_css_parser_t *parser, lxb_selectors_t *selectors, lxb_css_selector_list_t *list)
109+
{
110+
lxb_css_selector_list_destroy_memory(list);
111+
lxb_selectors_destroy(selectors);
112+
(void) lxb_css_parser_destroy(parser, false);
113+
}
114+
115+
static lxb_status_t php_dom_query_selector_common(
116+
zval *return_value,
117+
const xmlNode *root,
118+
zend_string *selectors_str,
119+
lxb_selectors_cb_f cb,
120+
void *ctx,
121+
lxb_selectors_opt_t options
122+
)
123+
{
124+
lxb_status_t status;
125+
126+
lxb_css_parser_t parser;
127+
lxb_selectors_t selectors;
128+
129+
lxb_css_selector_list_t *list = php_dom_parse_selector(&parser, &selectors, selectors_str, options);
130+
if (UNEXPECTED(list == NULL)) {
98131
status = LXB_STATUS_ERROR;
99132
} else {
100133
status = lxb_selectors_find(&selectors, root, list, cb, ctx);
101-
if (UNEXPECTED(status != LXB_STATUS_OK && status != LXB_STATUS_STOP)) {
102-
zend_argument_value_error(1, "contains an unsupported selector");
103-
}
134+
status = php_dom_check_css_execution_status(status);
104135
}
105136

106-
lxb_css_selector_list_destroy_memory(list);
107-
lxb_selectors_destroy(&selectors);
108-
(void) lxb_css_parser_destroy(&parser, false);
137+
php_dom_selector_cleanup(&parser, &selectors, list);
138+
139+
return status;
140+
}
141+
142+
static lxb_status_t php_dom_query_matches(
143+
zval *return_value,
144+
const xmlNode *root,
145+
zend_string *selectors_str,
146+
lxb_selectors_cb_f cb,
147+
void *ctx,
148+
lxb_selectors_opt_t options
149+
)
150+
{
151+
lxb_status_t status;
152+
153+
lxb_css_parser_t parser;
154+
lxb_selectors_t selectors;
155+
156+
lxb_css_selector_list_t *list = php_dom_parse_selector(&parser, &selectors, selectors_str, options);
157+
if (UNEXPECTED(list == NULL)) {
158+
status = LXB_STATUS_ERROR;
159+
} else {
160+
status = lxb_selectors_match_node(&selectors, root, list, cb, ctx);
161+
status = php_dom_check_css_execution_status(status);
162+
}
163+
164+
php_dom_selector_cleanup(&parser, &selectors, list);
109165

110166
return status;
111167
}
@@ -159,18 +215,13 @@ void dom_element_matches(xmlNodePtr thisp, dom_object *intern, zval *return_valu
159215
{
160216
dom_query_selector_matches_ctx ctx = { thisp, false };
161217

162-
const xmlNode *root = thisp;
163-
while (root->parent != NULL) {
164-
root = root->parent;
165-
}
166-
167-
if (php_dom_query_selector_common(
218+
if (php_dom_query_matches(
168219
return_value,
169-
root,
220+
thisp,
170221
selectors_str,
171222
php_dom_query_selector_find_matches_callback,
172223
&ctx,
173-
LXB_SELECTORS_OPT_DEFAULT
224+
LXB_SELECTORS_OPT_MATCH_FIRST
174225
) != LXB_STATUS_OK) {
175226
RETURN_THROWS();
176227
} else {

0 commit comments

Comments
 (0)