X-Git-Url: http://git.nguyen.vg/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fbindings%2Fc%2B%2B%2Ftatoo-engine.cc;fp=src%2Fbindings%2Fc%2B%2B%2Ftatoo-engine.cc;h=1ff2a49b06eccc805694fec71c521b00d3f391b3;hb=85ba2cc3211b4c6ea7da4cbaf9db3bd51765e6f7;hp=0000000000000000000000000000000000000000;hpb=33cc91c072d0c3ee3f17911f6484a24f55a3408b;p=tatoo.git diff --git a/src/bindings/c++/tatoo-engine.cc b/src/bindings/c++/tatoo-engine.cc new file mode 100644 index 0000000..1ff2a49 --- /dev/null +++ b/src/bindings/c++/tatoo-engine.cc @@ -0,0 +1,213 @@ +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "tatoo.h" + +namespace ml { +value pack(void *ptr) +{ + uintptr_t p = reinterpret_cast(ptr); + static_assert(sizeof(long) >= sizeof(uintptr_t), "We use long to store pointers"); + assert(!(p&1)); + return Val_long(p>>1); +} + +void* unpack(value val) { return reinterpret_cast(Long_val(val) << 1); } + +template +T* unpack(value val) { return reinterpret_cast(unpack(val)); } +} + +namespace xml { +xmlNode* node_first_child(xmlNode *node) +{ + switch(node->type) { + case XML_ELEMENT_NODE: + if(node->properties) { + return reinterpret_cast(node->properties); + break; + } + case XML_ATTRIBUTE_NODE: + case XML_DOCUMENT_NODE: + case XML_TEXT_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + return node->children; + default: + assert(false && "Unknown node type"); + } +} +xmlNode* node_next_sibling(xmlNode *node) +{ + if(node->next) + return node->next; + if(node->type == XML_ATTRIBUTE_NODE) + return node->parent->children; + return NULL; +} +} // namespace xml + +static value *init_document; +static value *xpath_compile; +static value *auto_evaluate; + +typedef std::vector nodelist; + +CAMLprim value node_getFirstChild(value node) +{ + CAMLparam1(node); + CAMLreturn(ml::pack(xml::node_first_child(ml::unpack(node)))); +} + +CAMLprim value node_getNextSibling(value node) +{ + CAMLparam1(node); + CAMLreturn(ml::pack(xml::node_next_sibling(ml::unpack(node)))); +} + +CAMLprim value node_getNodeType(value node) +{ + CAMLparam1(node); + CAMLreturn(Val_int(ml::unpack(node)->type)); +} + +CAMLprim value node_getNodeName(value node) +{ + CAMLparam1(node); + const xmlChar *name = ml::unpack(node)->name; + static const char *empty = ""; + CAMLreturn(caml_copy_string(name ? reinterpret_cast(name) : empty)); +} + +CAMLprim value node_getPreorder(value node) +{ + CAMLparam1(node); + CAMLreturn(Val_long(reinterpret_cast(ml::unpack(node)->_private))); +} + +CAMLprim value nodelist_getLength(value list) +{ + CAMLparam1(list); + CAMLreturn(Val_long(ml::unpack(list)->size())); +} + +CAMLprim value nodelist_item(value list, value idx) +{ + CAMLparam2(list, idx); + CAMLreturn(ml::pack(ml::unpack(list)->operator[](Long_val(idx)))); +} + +CAMLprim value nodelist_new(value unit) +{ + CAMLparam1(unit); + CAMLreturn(ml::pack(new nodelist)); // XXX: lifetime... +} + +CAMLprim value nodelist_add(value list, value node) +{ + CAMLparam2(list, node); + ml::unpack(list)->push_back(ml::unpack(node)); + CAMLreturn(list); +} + +CAMLprim value getNull(value unit) { CAMLparam1(unit); CAMLreturn(ml::pack(NULL)); } + +CAMLprim value dereference_object(value obj) +{ + CAMLparam1(obj); + //jni::env().DeleteGlobalRef(reinterpret_cast(obj)); + CAMLreturn(Val_unit); +} + +static uintptr_t decorate_(xmlNode *node, uintptr_t preorder) +{ + if(not node) return preorder; + + assert(!node->_private && "Non-null private data encountered"); + node->_private = reinterpret_cast(preorder++); + + preorder = decorate_(xml::node_first_child(node), preorder); + preorder = decorate_(xml::node_next_sibling(node), preorder); + + return preorder; +} + +static value decorate(xmlDoc *doc) +{ + uintptr_t size = decorate_(reinterpret_cast(doc), 0); + return caml_callback2(*init_document, ml::pack(doc), Val_long(size)); +} + +template +auto time(const char *msg, const Fn &fn, Args&&... args) -> decltype(fn(args...)) +{ + timespec start; + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start); + auto ret = fn(args...); + timespec end; + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end); + end.tv_nsec -= start.tv_nsec; + end.tv_sec -= start.tv_sec; + printf("\n---> %s: %.3f ms\n", msg, end.tv_sec * 1e3 + end.tv_nsec / 1e6); + return std::move(ret); +} + +static void process(const char *file, const char *expr) +{ + CAMLparam0(); + CAMLlocal3(docval, aut, res); + + xmlDoc *doc = time("parse", xmlReadFile, file, nullptr, 0); + + docval = time("decorate", decorate, doc); + + aut = time("compile", caml_callback, *xpath_compile, caml_copy_string(expr)); + + nodelist nl = { reinterpret_cast(doc) }; + res = time("evaluate", caml_callback3, *auto_evaluate, aut, docval, ml::pack(&nl)); + + nl = std::move(*ml::unpack(res)); + printf("\n---> Number of results: %zd\n", nl.size()); + /* for(auto node: nl) + printf("---> %s\n", node->name);*/ + + xmlFreeDoc(doc); + CAMLreturn0; +} + +void usage(const char *program) +{ + fprintf(stderr, + "Usage:\n" + " %s \n", program); + exit(1); +} + +int main(int argc, char *argv[]) +{ + LIBXML_TEST_VERSION; + + if(argc != 3) + usage(argv[0]); + + caml_startup(argv); + + init_document = caml_named_value("init_document"); assert(init_document); + xpath_compile = caml_named_value("xpath_compile"); assert(xpath_compile); + auto_evaluate = caml_named_value("auto_evaluate"); assert(auto_evaluate); + + process(argv[1], argv[2]); + + xmlCleanupParser(); + xmlMemoryDump(); + return 0; +}