diff options
| author | Arseny Kapoulkine <arseny.kapoulkine@gmail.com> | 2014-10-21 23:23:17 -0700 | 
|---|---|---|
| committer | Arseny Kapoulkine <arseny.kapoulkine@gmail.com> | 2014-10-21 23:23:17 -0700 | 
| commit | a55dfd3afaeef77db548ce629f7e40faee0690be (patch) | |
| tree | dd5c8dbca3a16f04492de05d02a31ef8ee61d0f6 | |
| parent | 457522a836f123653183c84fd77cc87e0078bc76 (diff) | |
| parent | 4a7762af9d96f8f12e8aa3f0c0899e9673d38d08 (diff) | |
Merge branch 'master' into compact
| -rw-r--r-- | src/pugixml.cpp | 240 | 
1 files changed, 137 insertions, 103 deletions
| diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 4bb0c86..c8dfb6c 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -7477,9 +7477,9 @@ PUGI__NS_BEGIN  		return node_is_before_sibling(ln, rn);  	} -	PUGI__FN bool node_is_ancestor(xml_node parent, xml_node node) +	PUGI__FN bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node)  	{ -		while (node && node != parent) node = node.parent(); +		while (node && node != parent) node = node->parent;  		return parent && node == parent;  	} @@ -8957,6 +8957,11 @@ PUGI__NS_BEGIN  			return false;  		} +		static bool eval_once(bool forward, nodeset_eval_t eval) +		{ +			return forward ? eval != nodeset_eval_all : eval == nodeset_eval_any; +		} +  		template <class Comp> static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp)  		{  			xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); @@ -9028,7 +9033,7 @@ PUGI__NS_BEGIN  			}  		} -		static void apply_predicate(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack) +		static void apply_predicate(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once)  		{  			assert(ns.size() >= first); @@ -9045,37 +9050,47 @@ PUGI__NS_BEGIN  				if (expr->rettype() == xpath_type_number)  				{  					if (expr->eval_number(c, stack) == i) +					{  						*last++ = *it; + +						if (once) break; +					}  				}  				else if (expr->eval_boolean(c, stack)) +				{  					*last++ = *it; + +					if (once) break; +				}  			}  			ns.truncate(last);  		} -		void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack) +		void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, nodeset_eval_t eval)  		{  			if (ns.size() == first) return; +			bool last_once = eval_once(ns.type() == xpath_node_set::type_sorted, eval); +  			for (xpath_ast_node* pred = _right; pred; pred = pred->_next)  			{ -				apply_predicate(ns, first, pred->_left, stack); +				apply_predicate(ns, first, pred->_left, stack, !pred->_next && last_once);  			}  		} -		bool step_push(xpath_node_set_raw& ns, const xml_attribute a, const xml_node parent, xpath_allocator* alloc) +		bool step_push(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* parent, xpath_allocator* alloc)  		{ -			if (!a) return false; +            assert(a); -			const char_t* name = a.name(); +			const char_t* name = a->name ? a->name : PUGIXML_TEXT("");  			switch (_test)  			{  			case nodetest_name:  				if (strequal(name, _data.nodetest) && is_xpath_attribute(name))  				{ -					ns.push_back(xpath_node(a, parent), alloc); +					ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);  					return true;  				}  				break; @@ -9084,7 +9099,7 @@ PUGI__NS_BEGIN  			case nodetest_all:  				if (is_xpath_attribute(name))  				{ -					ns.push_back(xpath_node(a, parent), alloc); +					ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);  					return true;  				}  				break; @@ -9092,7 +9107,7 @@ PUGI__NS_BEGIN  			case nodetest_all_in_namespace:  				if (starts_with(name, _data.nodetest) && is_xpath_attribute(name))  				{ -					ns.push_back(xpath_node(a, parent), alloc); +					ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);  					return true;  				}  				break; @@ -9104,68 +9119,70 @@ PUGI__NS_BEGIN  			return false;  		} -		bool step_push(xpath_node_set_raw& ns, const xml_node n, xpath_allocator* alloc) +		bool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc)  		{ -			if (!n) return false; +            assert(n); + +			xml_node_type type = PUGI__NODETYPE(n);  			switch (_test)  			{  			case nodetest_name: -				if (n.type() == node_element && strequal(n.name(), _data.nodetest)) +				if (type == node_element && n->name && strequal(n->name, _data.nodetest))  				{ -					ns.push_back(n, alloc); +					ns.push_back(xml_node(n), alloc);  					return true;  				}  				break;  			case nodetest_type_node: -				ns.push_back(n, alloc); +				ns.push_back(xml_node(n), alloc);  				return true;  			case nodetest_type_comment: -				if (n.type() == node_comment) +				if (type == node_comment)  				{ -					ns.push_back(n, alloc); +					ns.push_back(xml_node(n), alloc);  					return true;  				}  				break;  			case nodetest_type_text: -				if (n.type() == node_pcdata || n.type() == node_cdata) +				if (type == node_pcdata || type == node_cdata)  				{ -					ns.push_back(n, alloc); +					ns.push_back(xml_node(n), alloc);  					return true;  				}  				break;  			case nodetest_type_pi: -				if (n.type() == node_pi) +				if (type == node_pi)  				{ -					ns.push_back(n, alloc); +					ns.push_back(xml_node(n), alloc);  					return true;  				}  				break;  			case nodetest_pi: -				if (n.type() == node_pi && strequal(n.name(), _data.nodetest)) +				if (type == node_pi && n->name && strequal(n->name, _data.nodetest))  				{ -					ns.push_back(n, alloc); +					ns.push_back(xml_node(n), alloc);  					return true;  				}  				break;  			case nodetest_all: -				if (n.type() == node_element) +				if (type == node_element)  				{ -					ns.push_back(n, alloc); +					ns.push_back(xml_node(n), alloc);  					return true;  				}  				break;  			case nodetest_all_in_namespace: -				if (n.type() == node_element && starts_with(n.name(), _data.nodetest)) +				if (type == node_element && n->name && starts_with(n->name, _data.nodetest))  				{ -					ns.push_back(n, alloc); +					ns.push_back(xml_node(n), alloc);  					return true;  				}  				break; @@ -9177,7 +9194,7 @@ PUGI__NS_BEGIN  			return false;  		} -		template <class T> void step_fill(xpath_node_set_raw& ns, const xml_node n, xpath_allocator* alloc, bool once, T) +		template <class T> void step_fill(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc, bool once, T)  		{  			const axis_t axis = T::axis; @@ -9185,7 +9202,7 @@ PUGI__NS_BEGIN  			{  			case axis_attribute:  			{ -				for (xml_attribute a = n.first_attribute(); a; a = a.next_attribute()) +				for (xml_attribute_struct* a = n->first_attribute; a; a = a->next_attribute)  					if (step_push(ns, a, n, alloc) & once)  						return; @@ -9194,7 +9211,7 @@ PUGI__NS_BEGIN  			case axis_child:  			{ -				for (xml_node c = n.first_child(); c; c = c.next_sibling()) +				for (xml_node_struct* c = n->first_child; c; c = c->next_sibling)  					if (step_push(ns, c, alloc) & once)  						return; @@ -9208,23 +9225,25 @@ PUGI__NS_BEGIN  					if (step_push(ns, n, alloc) & once)  						return; -				xml_node cur = n.first_child(); +				xml_node_struct* cur = n->first_child; -				while (cur && cur != n) +				while (cur)  				{  					if (step_push(ns, cur, alloc) & once)  						return; -					if (cur.first_child()) -						cur = cur.first_child(); -					else if (cur.next_sibling()) -						cur = cur.next_sibling(); +					if (cur->first_child) +						cur = cur->first_child;  					else  					{ -						while (!cur.next_sibling() && cur != n) -							cur = cur.parent(); +						while (!cur->next_sibling) +						{ +							cur = cur->parent; + +							if (cur == n) return; +						} -						if (cur != n) cur = cur.next_sibling(); +						cur = cur->next_sibling;  					}  				} @@ -9233,7 +9252,7 @@ PUGI__NS_BEGIN  			case axis_following_sibling:  			{ -				for (xml_node c = n.next_sibling(); c; c = c.next_sibling()) +				for (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling)  					if (step_push(ns, c, alloc) & once)  						return; @@ -9242,7 +9261,7 @@ PUGI__NS_BEGIN  			case axis_preceding_sibling:  			{ -				for (xml_node c = n.previous_sibling(); c; c = c.previous_sibling()) +				for (xml_node_struct* c = n->prev_sibling_c; c->next_sibling; c = c->prev_sibling_c)  					if (step_push(ns, c, alloc) & once)  						return; @@ -9251,27 +9270,35 @@ PUGI__NS_BEGIN  			case axis_following:  			{ -				xml_node cur = n; +				xml_node_struct* cur = n;  				// exit from this node so that we don't include descendants -				while (cur && !cur.next_sibling()) cur = cur.parent(); -				cur = cur.next_sibling(); +				while (!cur->next_sibling) +				{ +					cur = cur->parent; + +					if (!cur) return; +				} + +				cur = cur->next_sibling;  				while (cur)  				{  					if (step_push(ns, cur, alloc) & once)  						return; -					if (cur.first_child()) -						cur = cur.first_child(); -					else if (cur.next_sibling()) -						cur = cur.next_sibling(); +					if (cur->first_child) +						cur = cur->first_child;  					else  					{ -						while (cur && !cur.next_sibling()) cur = cur.parent(); -						cur = cur.next_sibling(); +						while (!cur->next_sibling) +						{ +							cur = cur->parent; + +							if (!cur) return; +						} -						if (!cur) break; +						cur = cur->next_sibling;  					}  				} @@ -9280,40 +9307,40 @@ PUGI__NS_BEGIN  			case axis_preceding:  			{ -				xml_node cur = n; +				xml_node_struct* cur = n; -				while (cur && !cur.previous_sibling()) cur = cur.parent(); -				cur = cur.previous_sibling(); +				// exit from this node so that we don't include descendants +				while (!cur->prev_sibling_c->next_sibling) +				{ +					cur = cur->parent; + +					if (!cur) return; +				} + +				cur = cur->prev_sibling_c;  				while (cur)  				{ -					if (cur.last_child()) -						cur = cur.last_child(); +					if (cur->first_child) +						cur = cur->first_child->prev_sibling_c;  					else  					{  						// leaf node, can't be ancestor  						if (step_push(ns, cur, alloc) & once)  							return; -						if (cur.previous_sibling()) -							cur = cur.previous_sibling(); -						else +						while (!cur->prev_sibling_c->next_sibling)  						{ -							do  -							{ -								cur = cur.parent(); -								if (!cur) break; - -								if (!node_is_ancestor(cur, n)) -									if (step_push(ns, cur, alloc) & once) -										return; -							} -							while (!cur.previous_sibling()); +							cur = cur->parent; -							cur = cur.previous_sibling(); +							if (!cur) return; -							if (!cur) break; +							if (!node_is_ancestor(cur, n)) +								if (step_push(ns, cur, alloc) & once) +									return;  						} + +						cur = cur->prev_sibling_c;  					}  				} @@ -9327,14 +9354,14 @@ PUGI__NS_BEGIN  					if (step_push(ns, n, alloc) & once)  						return; -				xml_node cur = n.parent(); +				xml_node_struct* cur = n->parent;  				while (cur)  				{  					if (step_push(ns, cur, alloc) & once)  						return; -					cur = cur.parent(); +					cur = cur->parent;  				}  				break; @@ -9349,7 +9376,8 @@ PUGI__NS_BEGIN  			case axis_parent:  			{ -				if (n.parent()) step_push(ns, n.parent(), alloc); +				if (n->parent) +					step_push(ns, n->parent, alloc);  				break;  			} @@ -9359,7 +9387,7 @@ PUGI__NS_BEGIN  			}  		} -		template <class T> void step_fill(xpath_node_set_raw& ns, const xml_attribute a, const xml_node p, xpath_allocator* alloc, bool once, T v) +		template <class T> void step_fill(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* p, xpath_allocator* alloc, bool once, T v)  		{  			const axis_t axis = T::axis; @@ -9372,14 +9400,14 @@ PUGI__NS_BEGIN  					if (step_push(ns, a, p, alloc) & once)  						return; -				xml_node cur = p; +				xml_node_struct* cur = p;  				while (cur)  				{  					if (step_push(ns, cur, alloc) & once)  						return; -					cur = cur.parent(); +					cur = cur->parent;  				}  				break; @@ -9396,20 +9424,22 @@ PUGI__NS_BEGIN  			case axis_following:  			{ -				xml_node cur = p; +				xml_node_struct* cur = p; -				for (;;) +				while (cur)  				{ -					if (cur.first_child()) -						cur = cur.first_child(); -					else if (cur.next_sibling()) -						cur = cur.next_sibling(); +					if (cur->first_child) +						cur = cur->first_child;  					else  					{ -						while (cur && !cur.next_sibling()) cur = cur.parent(); -						cur = cur.next_sibling(); -						 -						if (!cur) break; +						while (!cur->next_sibling) +						{ +							cur = cur->parent; + +							if (!cur) return; +						} + +						cur = cur->next_sibling;  					}  					if (step_push(ns, cur, alloc) & once) @@ -9438,16 +9468,26 @@ PUGI__NS_BEGIN  			}  		} -		template <class T> xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval, T v) +		template <class T> void step_fill(xpath_node_set_raw& ns, const xpath_node& xn, xpath_allocator* alloc, bool once, T v)  		{  			const axis_t axis = T::axis;  			bool axis_has_attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self); + +			if (xn.node()) +				step_fill(ns, xn.node().internal_object(), alloc, once, v); +			else if (axis_has_attributes && xn.attribute() && xn.parent()) +				step_fill(ns, xn.attribute().internal_object(), xn.parent().internal_object(), alloc, once, v); +		} + +		template <class T> xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval, T v) +		{ +			const axis_t axis = T::axis;  			bool axis_reverse = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling);  			bool once =  				(axis == axis_attribute && _test == nodetest_name)  				? true -				: !_right && (axis_reverse ? eval == nodeset_eval_any : eval != nodeset_eval_all); +				: !_right && eval_once(!axis_reverse, eval);  			xpath_node_set_raw ns;  			ns.set_type(axis_reverse ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted); @@ -9466,22 +9506,14 @@ PUGI__NS_BEGIN  					// in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes  					if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted); -					if (it->node()) -						step_fill(ns, it->node(), stack.result, once, v); -					else if (axis_has_attributes && it->attribute() && it->parent()) -						step_fill(ns, it->attribute(), it->parent(), stack.result, once, v); -						 -					apply_predicates(ns, size, stack); +					step_fill(ns, *it, stack.result, once, v); +					apply_predicates(ns, size, stack, eval);  				}  			}  			else  			{ -				if (c.n.node()) -					step_fill(ns, c.n.node(), stack.result, once, v); -				else if (axis_has_attributes && c.n.attribute() && c.n.parent()) -					step_fill(ns, c.n.attribute(), c.n.parent(), stack.result, once, v); -				 -				apply_predicates(ns, 0, stack); +				step_fill(ns, c.n, stack.result, once, v); +				apply_predicates(ns, 0, stack, eval);  			}  			// child, attribute and self axes always generate unique set of nodes @@ -10116,7 +10148,9 @@ PUGI__NS_BEGIN  				// either expression is a number or it contains position() call; sort by document order  				if (_type == ast_filter) set.sort_do(); -				apply_predicate(set, 0, _right, stack); +				bool once = eval_once(set.type() == xpath_node_set::type_sorted, eval); + +				apply_predicate(set, 0, _right, stack, once);  				return set;  			} | 
