6 #include <caml/alloc.h>
7 #include <caml/callback.h>
8 #include <caml/memory.h>
10 #include <libxml/parser.h>
11 #include <libxml/tree.h>
18 uintptr_t p = reinterpret_cast<uintptr_t>(ptr);
19 static_assert(sizeof(long) >= sizeof(uintptr_t), "We use long to store pointers");
21 return Val_long(p>>1);
24 void* unpack(value val) { return reinterpret_cast<void *>(Long_val(val) << 1); }
27 T* unpack(value val) { return reinterpret_cast<T *>(unpack(val)); }
31 xmlNode* node_first_child(xmlNode *node)
34 case XML_ELEMENT_NODE:
35 if(node->properties) {
36 return reinterpret_cast<xmlNode *>(node->properties);
39 case XML_ATTRIBUTE_NODE:
40 case XML_DOCUMENT_NODE:
43 case XML_COMMENT_NODE:
44 return node->children;
46 assert(false && "Unknown node type");
49 xmlNode* node_next_sibling(xmlNode *node)
53 if(node->type == XML_ATTRIBUTE_NODE)
54 return node->parent->children;
59 static value *init_document;
60 static value *xpath_compile;
61 static value *auto_evaluate;
63 typedef std::vector<xmlNode *> nodelist;
65 CAMLprim value node_getFirstChild(value node)
68 CAMLreturn(ml::pack(xml::node_first_child(ml::unpack<xmlNode>(node))));
71 CAMLprim value node_getNextSibling(value node)
74 CAMLreturn(ml::pack(xml::node_next_sibling(ml::unpack<xmlNode>(node))));
77 CAMLprim value node_getNodeType(value node)
80 CAMLreturn(Val_int(ml::unpack<xmlNode>(node)->type));
83 CAMLprim value node_getNodeName(value node)
86 const xmlChar *name = ml::unpack<xmlNode>(node)->name;
87 static const char *empty = "";
88 CAMLreturn(caml_copy_string(name ? reinterpret_cast<const char *>(name) : empty));
91 CAMLprim value node_getPreorder(value node)
94 CAMLreturn(Val_long(reinterpret_cast<uintptr_t>(ml::unpack<xmlNode>(node)->_private)));
97 CAMLprim value nodelist_getLength(value list)
100 CAMLreturn(Val_long(ml::unpack<nodelist>(list)->size()));
103 CAMLprim value nodelist_item(value list, value idx)
105 CAMLparam2(list, idx);
106 CAMLreturn(ml::pack(ml::unpack<nodelist>(list)->operator[](Long_val(idx))));
109 CAMLprim value nodelist_new(value unit)
112 CAMLreturn(ml::pack(new nodelist)); // XXX: lifetime...
115 CAMLprim value nodelist_add(value list, value node)
117 CAMLparam2(list, node);
118 ml::unpack<nodelist>(list)->push_back(ml::unpack<xmlNode>(node));
122 CAMLprim value getNull(value unit) { CAMLparam1(unit); CAMLreturn(ml::pack(NULL)); }
124 CAMLprim value dereference_object(value obj)
127 //jni::env().DeleteGlobalRef(reinterpret_cast<jobject>(obj));
128 CAMLreturn(Val_unit);
131 static uintptr_t decorate_(xmlNode *node, uintptr_t preorder)
133 if(not node) return preorder;
135 assert(!node->_private && "Non-null private data encountered");
136 node->_private = reinterpret_cast<void *>(preorder++);
138 preorder = decorate_(xml::node_first_child(node), preorder);
139 preorder = decorate_(xml::node_next_sibling(node), preorder);
144 static value decorate(xmlDoc *doc)
146 uintptr_t size = decorate_(reinterpret_cast<xmlNode *>(doc), 0);
147 return caml_callback2(*init_document, ml::pack(doc), Val_long(size));
150 template<typename Fn, typename... Args>
151 auto time(const char *msg, const Fn &fn, Args&&... args) -> decltype(fn(args...))
154 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start);
155 auto ret = fn(args...);
157 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
158 end.tv_nsec -= start.tv_nsec;
159 end.tv_sec -= start.tv_sec;
160 printf("\n---> %s: %.3f ms\n", msg, end.tv_sec * 1e3 + end.tv_nsec / 1e6);
161 return std::move(ret);
164 static void process(const char *file, const char *expr)
167 CAMLlocal3(docval, aut, res);
169 xmlDoc *doc = time("parse", xmlReadFile, file, nullptr, 0);
171 docval = time("decorate", decorate, doc);
173 aut = time("compile", caml_callback, *xpath_compile, caml_copy_string(expr));
175 nodelist nl = { reinterpret_cast<xmlNode *>(doc) };
176 res = time("evaluate", caml_callback3, *auto_evaluate, aut, docval, ml::pack(&nl));
178 nl = std::move(*ml::unpack<nodelist>(res));
179 printf("\n---> Number of results: %zd\n", nl.size());
180 /* for(auto node: nl)
181 printf("---> %s\n", node->name);*/
187 void usage(const char *program)
191 " %s <file> <query>\n", program);
195 int main(int argc, char *argv[])
204 init_document = caml_named_value("init_document"); assert(init_document);
205 xpath_compile = caml_named_value("xpath_compile"); assert(xpath_compile);
206 auto_evaluate = caml_named_value("auto_evaluate"); assert(auto_evaluate);
208 process(argv[1], argv[2]);