It's sufficient to define PUGIXML_HEADER_ONLY anywhere now, source is included
automatically.
This is a second attempt; this time it includes a workaround for QMake bug
that caused it to generate incorrect Makefile.
Unfortunately, standard headers on MinGW32 insist on undefining off64_t
and _wfopen extensions if __STRICT_ANSI__ is true (e.g. C++11 mode). This
leads to compilation errors since b7a1fec started to use _wfopen in strict
mode. That change erroneously checked GCC version - however, the version
itself is irrelevant; the actual criteria is whether mingw64 runtime is
used.
off64_t is not useful on MinGW32 since we only need it to open large files
on 64-bit platforms; unfortunately, the lack of _wfopen means we won't be
able to support wide-char paths on Windows for MinGW32.
Fixes#24.
Since MinGW 4.5 does not define these functions if __STRICT_ANSI__ is defined
(in case of _wfopen it defines it inconsistently between stdio.h and wchar.h)
use the baseline functions for MinGW 4.5 and earlier.
Fixes#23.
node_copy_string relied on the fact that target node had an empty name and
value. Normally this is a safe assumption (and a good one to make since it
makes copying faster), however it was not checked and there was one case when
it did not hold.
Since we're reusing the logic for inserting nodes, newly inserted declaration
nodes had the name set automatically to xml, which in our case violates the
assumption and is counter-productive since we'll override the name right after
setting it.
For now the best solution is to do the same insertion manually - that results
in some code duplication that we can refactor later (same logic is partially
shared by _move variants anyway so on a level duplicating is not that bad).
Remove redundant this-> from type() call (argument used to be called type,
but it's now type_).
Use _root member directly when possible instead of calling internal_object.
Some compilers don't handle NaNs properly.
Some compilers don't implement fmod in a IEEE-compatible way.
Some compilers have exception handling codegen bugs (DMC...).
This should completely eliminate the confusion between load and load_file.
Of course, for compatibility reasons we have to preserve the old variant -
it will be deprecated in a future version and subsequently removed.
Previously push_back implementation was too big to inline; now the common case
(no realloc) is small and realloc variant is explicitly marked as no-inline.
This is similar to xml_allocator::allocate_memory/allocate_memory_oob and
makes some XPath queries 5% faster.
In some cases constant overhead on step evaluation is important - i.e. for
queries that evaluate a simple step in a predicate expression. Eliminating
a redundant function call thus can prove worthwhile.
This change makes some queries (e.g. //*[not(*)]) 4% faster.
Previously setting a large page size (i.e. 1M) would cause dynamic string
allocation to assert spuriously. A page size of 64K guarantees that all
offsets fit into 16 bits.
Split number/boolean filtering logic into two functions. This creates an
extra copy of a remove_if-like algorithm, but moves the type check out of
the loop and results in better organized filtering code.
Consolidate test-based dispatch into apply_predicate (which is now a member
function).
This lets us do fewer null pointer checks (making printing 2% faster with -O3)
and removes a lot of function calls (making printing 20% faster with -O0).
To get more benefits from constant predicate/filter optimization we rewrite
[position()=expr] predicates into [expr] for numeric expressions. Right now
the rewrite is only for entire expressions - it may be beneficial to split
complex expressions like [position()=constant and expr] into [constant][expr]
but that is more complicated.
last() does not depend on the node set contents so is "constant" as far as
our optimization is concerned so we can evaluate it once.
Numeric and boolean constant expressions in filters are different in that
to evaluate numeric expressions we need a sorted order, but to evaluate
boolean expressions we don't. The previously implemented optimization adds
an extra sorting step for constant boolean filters that will be more expensive
than redundant computations.
Since constant booleans are sort of an edge case, don't do this optimization.
This allows us to simplify apply_predicate_const to only handle numbers.
Now expression is always _right for filter/predicate nodes to make optimize()
simpler. Additionally we now use predicate metadata to make is_posinv_step()
faster.
This introduces a weak ordering dependency in rewrite rules to optimize() -
classification has to be performed before other optimizations.
If a filter/predicate expression is a constant, we don't need to evaluate it
for every nodeset element - we can evaluate it once and pick the right element
or keep/discard the entire collection.
If the expression is 1, we can early out on first node when evaluating the
node set - queries like following::item[1] are now significantly faster.
Additionally this change refactors filters/predicates to have additional
metadata describing the expression type in _test field that is filled during
optimization.
Note that predicate_constant selection right now is very simple (but captures
most common use cases except for maybe [last()]).
A page can fail to allocate during attribute creation; this case was not
previously handled.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1080 99668b35-9821-0410-8761-19e4c4f06640
When removing a node or attribute, we know that the parent has at least one
node/attribute so a null pointer check is redundant.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1078 99668b35-9821-0410-8761-19e4c4f06640
If the requested evaluation mode is not _all, we can use this mode for the
last predicate/filter expression and exit early.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1073 99668b35-9821-0410-8761-19e4c4f06640
Using pointers instead of node/attribute objects allows us to use knowledge
about the tree to guarantee that pointers are not null. This results in
less null checks (10-20% speedup with optimizations enabled) and less
function calls (5x speedup with optimizations disabled).
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1072 99668b35-9821-0410-8761-19e4c4f06640
This should never happen but can improve debugging experience for
work-in-progress changes since that avoids memcpy() into negative memory
space (debugger can't backtrace from failed memcpy since it does not set
up the stack frame).
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1070 99668b35-9821-0410-8761-19e4c4f06640
Some steps relied on step_push rejecting null inputs; this is no longer
the case. Additionally stepping now more rigorously filters null inputs.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1069 99668b35-9821-0410-8761-19e4c4f06640
Sometimes when evaluating the node set we don't need the entire set and
only need the first element in docorder or any element. In the absence of
iterator support we can still use this information to short-circuit
traversals.
This does not have any effect on straightforward node collection queries,
but frequently improves performance of complex queries with predicates
etc. XMark benchmark gets 15x faster with some queries enjoying 100x
speedup on 10 Mb dataset due to a significant complexity improvement.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1067 99668b35-9821-0410-8761-19e4c4f06640
Add documentation for xpath_query::evaluate_node and change
select_single_node to select_node in documentation and samples.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1066 99668b35-9821-0410-8761-19e4c4f06640
select_node is shorter and mistyping nodes as node or vice versa should
not lead to any issues since return types are substantially different.
select_single_node method still works and will be deprecated with an
attribute and removed at some point.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1065 99668b35-9821-0410-8761-19e4c4f06640
This method is equivalent to xml_node::select_single_node. This makes
select_single_node faster in certain cases by avoiding an allocation and -
more importantly - paves the way for future step optimizations.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1064 99668b35-9821-0410-8761-19e4c4f06640
Use descendant-or-self::node() transformation for self, descendant and
descendant-or-self axis. Self axis should be semi-frequent; descendant
axes should not really be used with // but if they ever are the complexity
of the step becomes quadratic so it's better to optimize this if possible.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1063 99668b35-9821-0410-8761-19e4c4f06640
CLR x64 JIT does not implement ceil() properly (ceil(-0.1) returns
positive zero instead of negative zero). Disable the relevant portions of
tests so that everything else is green...
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1062 99668b35-9821-0410-8761-19e4c4f06640
When looking for an attribute by name, finding the first attribute means
we can stop looking since attribute names are unique. This makes some
queries faster by 40%.
Another very common pattern in XPath queries is finding an attribute with
a specified value using a predicate (@name = 'value'). While we perform an
optimal amount of traversal in that case, there is a substantial overhead
with evaluating the nodes, saving and restoring the stack state, pushing
the attribute node into a set, etc. Detecting this pattern allows us to
use optimized code, resulting in up to 2x speedup for some queries.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1061 99668b35-9821-0410-8761-19e4c4f06640
The actual condition for the optimization is invariance from context list
-- this includes both position() and last().
Instead of splitting the posinv concept just include last() into
non-posinv expressions - this requires sorting for boolean predicates that
depend on last() and do not depend on position(). These cases should be
very rare.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1060 99668b35-9821-0410-8761-19e4c4f06640
Comment value can not contain the string "--" or end with "-". Since
comments do not support escaping, we're handling this by adding an extra
space after the first "-". A string of "-" thus turns into "- - - ...".
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1058 99668b35-9821-0410-8761-19e4c4f06640
All ad-hoc attribute operations are now implemented as explicit low-level
functions, and xml_node just uses them. Additionally extract commonly used
is_attribute_of and move detaching of node from append_node to remove_node
- append_node now only works on detached nodes (small increase in parsing
performance).
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1056 99668b35-9821-0410-8761-19e4c4f06640
When xpath_string is heap-allocated we always know the length of the
string at some point - it is now stored in the object. This reduces
redundant string length calculations and makes string_value() much faster
in case it has to concatenate strings.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1053 99668b35-9821-0410-8761-19e4c4f06640
translate() with constant arguments now uses a 128-byte table and a table
lookup instead of searching characters in the source string. The table is
generated during query optimization.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1052 99668b35-9821-0410-8761-19e4c4f06640
Node ancestor search now terminates early if ancestor is found before the
document root (only happens if nodes were at the same depth).
Sibling search now steps synchronously for left and right nodes to avoid
worst-case performance when we go in the wrong direction and have to scan
a big list (this comes at the cost of average performance since in the
best case we do 2x more operations).
Node comparison is now done using node pointers to elide some null
comparisons since the structure of the search guarantees that they are
handled properly.
All of the above results in ~2x faster document order comparison on
complex documents.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1050 99668b35-9821-0410-8761-19e4c4f06640
XPath evaluation frequently produces sequences that are sorted but are not
tagged as such (area for improvement...). Doing a linear scan before
sorting is cheap and results in tremendous speedup for already sorted
sequences (especially if document_buffer_order optimization does not
apply).
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1049 99668b35-9821-0410-8761-19e4c4f06640
While gcc and clang can eliminate dependency on s in the inner loop of
PUGI__SCANWHILE_UNROLL, MSVC emits a series of register increments.
Rewriting the code to explicitly remove the dependency keeps similar
codegen on gcc/clang but improves codegen on MSVC for a 10% performance
boost.
Also use unrolled scanning in text_output_escaped (2% faster).
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1048 99668b35-9821-0410-8761-19e4c4f06640
The page no longer contains 'data' field to use sizeof everywhere instead
of offsetof/sizeof inconsistency (that is required because some compilers
don't recognize offsetof as compile-time constant).
The page no longer contains 'memory' field that is now encoded as an
offset byte before the page - this allows us to save one pointer from the
static page in the document to keep the size the same as in v1.2 (binary
compatibility).
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1046 99668b35-9821-0410-8761-19e4c4f06640
Use the same flag that is used for marking name/value in nodes/attributes
as shared. This reduces document structure size and makes some amount of
sense (although admittedly is a bit of a hack).
We need to bring document _memory size back down to 192 bytes and this is
the first step.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1045 99668b35-9821-0410-8761-19e4c4f06640
Also fixes PUGIXML_NO_STL compilation and makes it possible to build with
any version of new Windows SDK.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1044 99668b35-9821-0410-8761-19e4c4f06640
xml_node objects carry an overhead since they perform NULL checks - in
case of copying a hierarchy we know that we only traverse valid nodes so
we don't need to do this. This makes copyless copy 16% faster.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1043 99668b35-9821-0410-8761-19e4c4f06640
This bypasses the allow_insert check (which is redundant for copying since
we're mirroring an existing node structure that must be valid) and does
not cause an extra allocation for new declaration nodes. Overall results
in 15% faster copying,
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1036 99668b35-9821-0410-8761-19e4c4f06640
Moving nodes results in node order being different from order of allocated
names/values; since move is O(1) we can't mark the moved nodes in a
subtree so we have to disable the optimization for the entire document.
Similarly, if a node is composed of multiple buffers, comparing nodes in
different buffers does not result in meaningful order.
Since we value correctness over performance, mark the entire document in
these cases to disable sorting optimization.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1034 99668b35-9821-0410-8761-19e4c4f06640
Now copying nodes or attributes does not copy names/values if the source
strings are in a document buffer. As a result, several nodes can now share
the same string in document buffer - to support this we 'taint' both
source and destination with a special 'shared' bit.
Tainting disables offset_debug() and fast-path document order comparison;
it also prevents strcpy_insitu from reusing the document buffer memory for
the copied node.
The downsides include slower XPath queries in some (rare) cases and
slightly higher memory consumption in some (rare) cases.
XPath queries can execute slower if a lot of old nodes were copied to new
nodes *and* a query only touches old nodes (so it used to benefit a lot
from fast comparison path) *and* a query produces unsorted node sets that
need to be sorted later (both are relatively rare).
Higher memory consumption is possible if a lot of nodes were copied and
all nodes (both new and old) have their contents modified 'in place' --
previously we could modify the old node in place and the new node required
one allocation on copy, and now both nodes have to have their data
allocated during modification. This should also be rare.
On the bright side, in a lot of cases copying of string data can be
avoided - this makes the copy much faster and the document now occupies
less memory. For example, some uses of append_buffer are now actually slower
compared to building up a document by copying a template from the same
document and modifying the copy slightly.
In one of the internal benchmarks copying is now 4x faster (the difference
can be more dramatic with more string contents and less markup).
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1032 99668b35-9821-0410-8761-19e4c4f06640
This is required to make it possible to use a pointer to one of the
buffers with the document data in nodes but keep offset_debug and (more
importantly) XPath document order comparison optimization working.
The change increases memory page alignment to 64 bytes (so requires +32
bytes for every page allocation, which should not be a problem - even with
non-default 4k pages this is <1% extra cost, with default 32k pages the
overhead is 0.1%)
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1031 99668b35-9821-0410-8761-19e4c4f06640
Since xml_node/attribute are pointer wrappers it's cheaper to pass them by
value. This makes XPath evaluation 4% faster and node printing 2% faster.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1029 99668b35-9821-0410-8761-19e4c4f06640
This makes node copying 6% faster, prevents it from ever running out of
stack space and makes the profiling results more actionable for profilers
that can't merge information from recursive calls.
git-svn-id: https://pugixml.googlecode.com/svn/trunk@1027 99668b35-9821-0410-8761-19e4c4f06640