[xslt] speeding up xslt in gtk-doc
- From: Stefan Kost <ensonic hora-obscura de>
- To: "xslt gnome org" <xslt gnome org>
- Subject: [xslt] speeding up xslt in gtk-doc
- Date: Tue, 03 May 2011 18:14:44 +0300
hi,
I am still not happy with the time it takes for gtk-doc to generate the
html. I did some profiling and tired various changes. Its not too
impressive. Just posting them here for feedback and comment on the
directions of what would be acceptable or not. I technically have commit
rights, so I can push things once they are ready. If patch 0002 looks
like a good idea, I can extend it for other accessors.
Stefan
Test case was generating the html for gstreamer-core api docs
real user sys
------------------------------ before
1m22.872s 1m17.317s 0m1.444s
1m19.261s 1m17.437s 0m1.384s
1m19.770s 1m17.417s 0m1.264s
------------------------------ 0001-xpath-annotate-branch-prediction.patch
1m18.123s 1m16.677s 0m1.256s
1m18.684s 1m17.181s 0m1.292s
1m18.887s 1m17.217s 0m1.364s
------------------------------
0002-xpath-split-traversal-into-init-and-next-functions.patch
1m18.537s 1m16.925s 0m1.388s
1m18.616s 1m16.913s 0m1.412s
1m18.249s 1m16.653s 0m1.328s
------------------------------
0003-xpath-avoid-a-memcpy-on-the-expense-of-temporarily-w.patch
1m17.481s 1m16.137s 0m1.208s
1m17.977s 1m16.481s 0m1.328s
1m17.791s 1m16.413s 0m1.232s
>From 144d36fbdd4ff3fec27f50189617bdeb8979a4bf Mon Sep 17 00:00:00 2001
From: Stefan Kost <ensonic users sf net>
Date: Tue, 3 May 2011 17:21:57 +0300
Subject: [PATCH 1/4] xpath: annotate branch prediction
---
include/libxml/xpathInternals.h | 29 ++++++++++++++------
xpath.c | 56 ++++++++++++++++++++------------------
2 files changed, 49 insertions(+), 36 deletions(-)
diff --git a/include/libxml/xpathInternals.h b/include/libxml/xpathInternals.h
index dcd5243..f384e1a 100644
--- a/include/libxml/xpathInternals.h
+++ b/include/libxml/xpathInternals.h
@@ -21,6 +21,17 @@
extern "C" {
#endif
+/*
+ * Ideally have this for whole libxml2
+ */
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+#define XML_LIKELY(expr) (__builtin_expect ((expr), 1))
+#define XML_UNLIKELY(expr) (__builtin_expect ((expr), 0))
+#else
+#define XML_LIKELY(expr) (expr)
+#define XML_UNLIKELY(expr) (expr)
+#endif
+
/************************************************************************
* *
* Helpers *
@@ -237,7 +248,7 @@ XMLPUBFUN void * XMLCALL
* Macro to return from the function if an XPath error was detected.
*/
#define CHECK_ERROR \
- if (ctxt->error != XPATH_EXPRESSION_OK) return
+ if (XML_UNLIKELY (ctxt->error != XPATH_EXPRESSION_OK)) return
/**
* CHECK_ERROR0:
@@ -245,7 +256,7 @@ XMLPUBFUN void * XMLCALL
* Macro to return 0 from the function if an XPath error was detected.
*/
#define CHECK_ERROR0 \
- if (ctxt->error != XPATH_EXPRESSION_OK) return(0)
+ if (XML_UNLIKELY (ctxt->error != XPATH_EXPRESSION_OK)) return(0)
/**
* XP_ERROR:
@@ -273,7 +284,7 @@ XMLPUBFUN void * XMLCALL
* type.
*/
#define CHECK_TYPE(typeval) \
- if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \
+ if (XML_UNLIKELY ((ctxt->value == NULL) || (ctxt->value->type != typeval))) \
XP_ERROR(XPATH_INVALID_TYPE)
/**
@@ -284,7 +295,7 @@ XMLPUBFUN void * XMLCALL
* type. Return(0) in case of failure
*/
#define CHECK_TYPE0(typeval) \
- if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \
+ if (XML_UNLIKELY ((ctxt->value == NULL) || (ctxt->value->type != typeval))) \
XP_ERROR0(XPATH_INVALID_TYPE)
/**
@@ -294,8 +305,8 @@ XMLPUBFUN void * XMLCALL
* Macro to check that the number of args passed to an XPath function matches.
*/
#define CHECK_ARITY(x) \
- if (ctxt == NULL) return; \
- if (nargs != (x)) \
+ if (XML_UNLIKELY (ctxt == NULL)) return; \
+ if (XML_UNLIKELY (nargs != (x))) \
XP_ERROR(XPATH_INVALID_ARITY);
/**
@@ -304,7 +315,7 @@ XMLPUBFUN void * XMLCALL
* Macro to try to cast the value on the top of the XPath stack to a string.
*/
#define CAST_TO_STRING \
- if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_STRING)) \
+ if (XML_LIKELY ((ctxt->value != NULL) && (ctxt->value->type != XPATH_STRING))) \
xmlXPathStringFunction(ctxt, 1);
/**
@@ -313,7 +324,7 @@ XMLPUBFUN void * XMLCALL
* Macro to try to cast the value on the top of the XPath stack to a number.
*/
#define CAST_TO_NUMBER \
- if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_NUMBER)) \
+ if (XML_LIKELY ((ctxt->value != NULL) && (ctxt->value->type != XPATH_NUMBER))) \
xmlXPathNumberFunction(ctxt, 1);
/**
@@ -322,7 +333,7 @@ XMLPUBFUN void * XMLCALL
* Macro to try to cast the value on the top of the XPath stack to a boolean.
*/
#define CAST_TO_BOOLEAN \
- if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_BOOLEAN)) \
+ if (XML_LIKELY ((ctxt->value != NULL) && (ctxt->value->type != XPATH_BOOLEAN))) \
xmlXPathBooleanFunction(ctxt, 1);
/*
diff --git a/xpath.c b/xpath.c
index 608fe00..579db1b 100644
--- a/xpath.c
+++ b/xpath.c
@@ -2410,7 +2410,7 @@ valuePop(xmlXPathParserContextPtr ctxt)
{
xmlXPathObjectPtr ret;
- if ((ctxt == NULL) || (ctxt->valueNr <= 0))
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->valueNr <= 0)))
return (NULL);
ctxt->valueNr--;
if (ctxt->valueNr > 0)
@@ -2433,8 +2433,9 @@ valuePop(xmlXPathParserContextPtr ctxt)
int
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
{
- if ((ctxt == NULL) || (value == NULL)) return(-1);
- if (ctxt->valueNr >= ctxt->valueMax) {
+ if (XML_UNLIKELY((ctxt == NULL) || (value == NULL)))
+ return(-1);
+ if (XML_UNLIKELY(ctxt->valueNr >= ctxt->valueMax)) {
xmlXPathObjectPtr *tmp;
tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
@@ -7524,7 +7525,7 @@ typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
*/
xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
- if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
if (cur == NULL)
return(ctxt->context->node);
return(NULL);
@@ -7542,10 +7543,11 @@ xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
*/
xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
- if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
- if (cur == NULL) {
- if (ctxt->context->node == NULL) return(NULL);
- switch (ctxt->context->node->type) {
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
+ if (XML_UNLIKELY(cur == NULL)) {
+ cur = ctxt->context->node;
+ if (XML_UNLIKELY(cur == NULL)) return(NULL);
+ switch (cur->type) {
case XML_ELEMENT_NODE:
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
@@ -7555,7 +7557,7 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
case XML_COMMENT_NODE:
case XML_NOTATION_NODE:
case XML_DTD_NODE:
- return(ctxt->context->node->children);
+ return(cur->children);
case XML_DOCUMENT_NODE:
case XML_DOCUMENT_TYPE_NODE:
case XML_DOCUMENT_FRAG_NODE:
@@ -7563,7 +7565,7 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
#ifdef LIBXML_DOCB_ENABLED
case XML_DOCB_DOCUMENT_NODE:
#endif
- return(((xmlDocPtr) ctxt->context->node)->children);
+ return(((xmlDocPtr) cur)->children);
case XML_ELEMENT_DECL:
case XML_ATTRIBUTE_DECL:
case XML_ENTITY_DECL:
@@ -7575,8 +7577,8 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
}
return(NULL);
}
- if ((cur->type == XML_DOCUMENT_NODE) ||
- (cur->type == XML_HTML_DOCUMENT_NODE))
+ if (XML_UNLIKELY((cur->type == XML_DOCUMENT_NODE) ||
+ (cur->type == XML_HTML_DOCUMENT_NODE)))
return(NULL);
return(cur->next);
}
@@ -7593,8 +7595,8 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
*/
static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
- if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
- if (cur == NULL) {
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
+ if (XML_UNLIKELY(cur == NULL)) {
cur = ctxt->context->node;
if (cur == NULL) return(NULL);
/*
@@ -7745,7 +7747,7 @@ next_sibling:
*/
xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
- if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
if (cur == NULL) {
if (ctxt->context->node == NULL)
return(NULL);
@@ -7808,7 +7810,7 @@ xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
*/
xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
- if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
if (cur == NULL) {
if (ctxt->context->node == NULL)
return(NULL);
@@ -7833,7 +7835,7 @@ xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
*/
xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
- if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
/*
* the parent of an attribute or namespace node is the element
* to which the attribute or namespace node is attached
@@ -7906,7 +7908,7 @@ xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
*/
xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
- if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
/*
* the parent of an attribute or namespace node is the element
* to which the attribute or namespace node is attached
@@ -8030,7 +8032,7 @@ xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
*/
xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
- if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
if (cur == NULL)
return(ctxt->context->node);
return(xmlXPathNextAncestor(ctxt, cur));
@@ -8049,7 +8051,7 @@ xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
*/
xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
- if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
(ctxt->context->node->type == XML_NAMESPACE_DECL))
return(NULL);
@@ -8074,7 +8076,7 @@ xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
*/
xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
- if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
(ctxt->context->node->type == XML_NAMESPACE_DECL))
return(NULL);
@@ -8105,7 +8107,7 @@ xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
*/
xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
- if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
(cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
return(cur->children);
@@ -8169,7 +8171,7 @@ xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
{
- if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
if (cur == NULL) {
cur = ctxt->context->node;
if (cur->type == XML_NAMESPACE_DECL)
@@ -8215,7 +8217,7 @@ static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
xmlNodePtr cur)
{
- if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
if (cur == NULL) {
cur = ctxt->context->node;
if (cur == NULL)
@@ -8258,7 +8260,7 @@ xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
*/
xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
- if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
if (ctxt->context->tmpNsList != NULL)
@@ -8295,7 +8297,7 @@ xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
*/
xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
- if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
if (ctxt->context->node == NULL)
return(NULL);
if (ctxt->context->node->type != XML_ELEMENT_NODE)
@@ -9740,7 +9742,7 @@ xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
xmlChar *ret;
int count = 0;
- if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
+ if (XML_UNLIKELY((ctxt == NULL) || (ctxt->cur == NULL))) return(NULL);
/*
* Accelerator for simple ASCII names
*/
--
1.7.1
>From c25ad12939a227dd0ae7cb0c4efd3e27f6e05e8b Mon Sep 17 00:00:00 2001
From: Stefan Kost <ensonic users sf net>
Date: Tue, 3 May 2011 17:22:40 +0300
Subject: [PATCH 2/4] xpath: split traversal into init and next functions
This avoid us checking cur=NULL in next().
---
xpath.c | 98 ++++++++++++++++++++++++++++++++++++--------------------------
1 files changed, 57 insertions(+), 41 deletions(-)
diff --git a/xpath.c b/xpath.c
index 579db1b..476ac9d 100644
--- a/xpath.c
+++ b/xpath.c
@@ -7487,6 +7487,12 @@ xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
* *
************************************************************************/
+ /*
+ * A function to initialize traversal.
+ */
+typedef xmlNodePtr (*xmlXPathTraversalStartFunction)
+ (xmlXPathParserContextPtr ctxt);
+
/*
* A traversal function enumerates nodes along an axis.
* Initially it must be called with NULL, and it indicates
@@ -7584,6 +7590,51 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
}
/**
+ * xmlXPathFirstChildElement:
+ * @ctxt: the XPath Parser context
+ *
+ * Init traversal for the "child" direction and nodes of type element.
+ * The child axis contains the children of the context node in document order.
+ *
+ * Returns the first element following that axis
+ */
+static xmlNodePtr
+xmlXPathFirstChildElement(xmlXPathParserContextPtr ctxt) {
+ xmlNodePtr cur = ctxt->context->node;
+
+ if (XML_UNLIKELY(cur == NULL)) return(NULL);
+ /*
+ * Get the first element child.
+ */
+ switch (cur->type) {
+ case XML_ELEMENT_NODE:
+ case XML_DOCUMENT_FRAG_NODE:
+ case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
+ case XML_ENTITY_NODE:
+ cur = cur->children;
+ if (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE)
+ return(cur);
+ do {
+ cur = cur->next;
+ } while ((cur != NULL) &&
+ (cur->type != XML_ELEMENT_NODE));
+ return(cur);
+ }
+ return(NULL);
+ case XML_DOCUMENT_NODE:
+ case XML_HTML_DOCUMENT_NODE:
+#ifdef LIBXML_DOCB_ENABLED
+ case XML_DOCB_DOCUMENT_NODE:
+#endif
+ return(xmlDocGetRootElement((xmlDocPtr) cur));
+ default:
+ return(NULL);
+ }
+ return(NULL);
+}
+
+/**
* xmlXPathNextChildElement:
* @ctxt: the XPath Parser context
* @cur: the current node in the traversal
@@ -7595,40 +7646,6 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
*/
static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
- if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL);
- if (XML_UNLIKELY(cur == NULL)) {
- cur = ctxt->context->node;
- if (cur == NULL) return(NULL);
- /*
- * Get the first element child.
- */
- switch (cur->type) {
- case XML_ELEMENT_NODE:
- case XML_DOCUMENT_FRAG_NODE:
- case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
- case XML_ENTITY_NODE:
- cur = cur->children;
- if (cur != NULL) {
- if (cur->type == XML_ELEMENT_NODE)
- return(cur);
- do {
- cur = cur->next;
- } while ((cur != NULL) &&
- (cur->type != XML_ELEMENT_NODE));
- return(cur);
- }
- return(NULL);
- case XML_DOCUMENT_NODE:
- case XML_HTML_DOCUMENT_NODE:
-#ifdef LIBXML_DOCB_ENABLED
- case XML_DOCB_DOCUMENT_NODE:
-#endif
- return(xmlDocGetRootElement((xmlDocPtr) cur));
- default:
- return(NULL);
- }
- return(NULL);
- }
/*
* Get the next sibling element node.
*/
@@ -11979,6 +11996,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
int hasPredicateRange, hasAxisRange, pos, size, newSize;
int breakOnFirstHit;
+ xmlXPathTraversalStartFunction next_i = NULL;
xmlXPathTraversalFunction next = NULL;
/* compound axis traversal */
xmlXPathTraversalFunctionExt outerNext = NULL;
@@ -12044,6 +12062,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
/*
* Optimization if an element node type is 'element'.
*/
+ next_i = xmlXPathFirstChildElement;
next = xmlXPathNextChildElement;
} else
next = xmlXPathNextChild;
@@ -12205,13 +12224,9 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
* Traverse the axis and test the nodes.
*/
pos = 0;
- cur = NULL;
+ cur = next_i ? next_i(ctxt) : next(ctxt, NULL);
hasNsNodes = 0;
- do {
- cur = next(ctxt, cur);
- if (cur == NULL)
- break;
-
+ while (cur) {
/*
* QUESTION TODO: What does the "first" and "last" stuff do?
*/
@@ -12390,7 +12405,8 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
}
break;
} /* switch(test) */
- } while (cur != NULL);
+ cur = next(ctxt, cur);
+ };
goto apply_predicates;
--
1.7.1
>From 7066379eb1ef02f68f1cf66168771e13b39cc765 Mon Sep 17 00:00:00 2001
From: Stefan Kost <ensonic users sf net>
Date: Tue, 3 May 2011 17:25:39 +0300
Subject: [PATCH 4/4] xpath: avoid a memcpy on the expense of temporarily wasting memory
Just allocate a target buffer and fill, instead of printing to a temp buffer and
then dup'ing.
---
xpath.c | 7 +++----
1 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/xpath.c b/xpath.c
index 6b2f627..384a36c 100644
--- a/xpath.c
+++ b/xpath.c
@@ -5586,10 +5586,9 @@ xmlXPathCastNumberToString (double val) {
ret = xmlStrdup((const xmlChar *) "0");
} else {
/* could be improved */
- char buf[100];
- xmlXPathFormatNumber(val, buf, 99);
- buf[99] = 0;
- ret = xmlStrdup((const xmlChar *) buf);
+ ret = xmlMalloc(100);
+ xmlXPathFormatNumber(val, ret, 99);
+ ret[99] = 0;
}
}
return(ret);
--
1.7.1
[Date Prev][
Date Next] [Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]