Skip to content

Commit cc77007

Browse files
committed
Use boost::shared_ptr to always free memory
1 parent c9494cc commit cc77007

File tree

4 files changed

+32
-38
lines changed

4 files changed

+32
-38
lines changed

src/xml2_node.cpp

+8-26
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#include <Rcpp.h>
22
#include <libxml/tree.h>
3+
#include <boost/shared_ptr.hpp>
34

45
using namespace Rcpp;
56
#include "xml2_types.h"
6-
#include "xml2_utils.h"
77

88
// [[Rcpp::export]]
99
CharacterVector node_name(XPtrNode node) {
@@ -12,36 +12,22 @@ CharacterVector node_name(XPtrNode node) {
1212

1313
// [[Rcpp::export]]
1414
CharacterVector node_text(XPtrNode node) {
15-
xmlChar* s = xmlNodeGetContent(node.get());
16-
CharacterVector out = xmlCharToRChar(s);
17-
if (s != NULL)
18-
xmlFree(s);
19-
20-
return out;
15+
return Xml2Char(xmlNodeGetContent(node.get())).string();
2116
}
2217

2318
// [[Rcpp::export]]
2419
CharacterVector node_attr(XPtrNode node, std::string name) {
25-
xmlChar* s = xmlGetProp(node.get(), (xmlChar*) name.c_str());
26-
27-
CharacterVector out = xmlCharToRChar(s);
28-
if (s != NULL)
29-
xmlFree(s);
30-
31-
return out;
20+
return Xml2Char(xmlGetProp(node.get(), (xmlChar*) name.c_str())).string();
3221
}
3322

3423
// [[Rcpp::export]]
3524
CharacterVector node_format(XPtrDoc doc, XPtrNode node,
3625
bool format = true,
3726
int indent = 0) {
38-
xmlBufferPtr buffer = xmlBufferCreate();
39-
xmlNodeDump(buffer, doc.get(), node.get(), indent, format);
27+
boost::shared_ptr<xmlBuffer> buffer(xmlBufferCreate(), xmlFree);
28+
xmlNodeDump(buffer.get(), doc.get(), node.get(), indent, format);
4029

41-
CharacterVector out = xmlCharToRChar(buffer->content);
42-
xmlFree(buffer);
43-
44-
return out;
30+
return xmlCharToRChar(buffer->content);
4531
}
4632

4733
// [[Rcpp::export]]
@@ -70,10 +56,6 @@ void node_write(XPtrNode n, XPtrDoc d, std::string path) {
7056

7157
// [[Rcpp::export]]
7258
CharacterVector node_path(XPtrNode n) {
73-
xmlChar* s = xmlGetNodePath(n.get());
74-
CharacterVector out = xmlCharToRChar(s);
75-
if (s != NULL)
76-
xmlFree(s);
77-
78-
return out;
59+
return Xml2Char(xmlGetNodePath(n.get())).string();
7960
}
61+

src/xml2_types.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
#ifndef __XML2_XML2_TYPES__
22
#define __XML2_XML2_TYPES__
33

4-
#include <RcppCommon.h>
5-
#include <libxml/parser.h>
4+
#include "xml2_utils.h"
65
#include "XmlPushParser.h"
6+
#include <libxml/tree.h>
7+
#include <Rcpp.h>
78

89
inline void finaliseNode(xmlNode* node) {
910
// do nothing

src/xml2_utils.h

+13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <Rcpp.h>
55
#include <libxml/tree.h>
6+
#include <boost/shared_ptr.hpp>
67

78
inline Rcpp::CharacterVector xmlCharToRChar(const xmlChar* x) {
89
if (x == NULL)
@@ -14,4 +15,16 @@ inline Rcpp::CharacterVector xmlCharToRChar(const xmlChar* x) {
1415
return out;
1516
}
1617

18+
// A wrapper around xmlChar* that always frees memory
19+
class Xml2Char {
20+
boost::shared_ptr<xmlChar> string_;
21+
22+
public:
23+
Xml2Char(xmlChar* string): string_(string, xmlFree) {}
24+
25+
Rcpp::CharacterVector string() {
26+
return xmlCharToRChar(string_.get());
27+
}
28+
};
29+
1730
#endif

src/xml2_xpath.cpp

+8-10
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,23 @@ using namespace Rcpp;
66

77
// [[Rcpp::export]]
88
Rcpp::List node_search(XPtrNode node, XPtrDoc doc, std::string xpath) {
9-
xmlXPathContextPtr context = xmlXPathNewContext(doc.get());
10-
xmlXPathObjectPtr result = xmlXPathNodeEval(
11-
node.get(),
12-
(xmlChar*) xpath.c_str(),
13-
context
9+
10+
boost::shared_ptr<xmlXPathContext> context(
11+
xmlXPathNewContext(doc.get()),
12+
xmlXPathFreeContext
13+
);
14+
boost::shared_ptr<xmlXPathObject> result(
15+
xmlXPathNodeEval(node.get(), (xmlChar*) xpath.c_str(), context.get()),
16+
xmlXPathFreeObject
1417
);
15-
xmlXPathFreeContext(context);
1618

1719
if (result->type != XPATH_NODESET) {
18-
xmlXPathFreeObject(result);
1920
Rcpp::stop("Currently only nodeset results are supported");
2021
}
2122

2223
// Return an empty list if there are no matches
2324
xmlNodeSetPtr nodes = result->nodesetval;
2425
if (xmlXPathNodeSetIsEmpty(nodes)) {
25-
xmlXPathFreeObject(result);
2626
return Rcpp::List::create();
2727
}
2828

@@ -31,8 +31,6 @@ Rcpp::List node_search(XPtrNode node, XPtrDoc doc, std::string xpath) {
3131
for (int i = 0; i < nodes->nodeNr; i++) {
3232
out[i] = XPtrNode(nodes->nodeTab[i]);
3333
}
34-
xmlXPathFreeObject(result);
35-
3634

3735
return out;
3836
}

0 commit comments

Comments
 (0)