-\r
-/******************************************************************************\r
- * Copyright (C) 2008 by Diego Arroyuelo *\r
- * Interface for the in-memory XQuery/XPath engine *\r
- * *\r
- * This program is free software; you can redistribute it and/or modify *\r
- * it under the terms of the GNU Lesser General Public License as published *\r
- * by the Free Software Foundation; either version 2 of the License, or *\r
- * (at your option) any later version. *\r
- * *\r
- * This program is distributed in the hope that it will be useful, *\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *\r
- * GNU Lesser General Public License for more details. *\r
- * *\r
- * You should have received a copy of the GNU Lesser General Public License *\r
- * along with this program; if not, write to the *\r
- * Free Software Foundation, Inc., *\r
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *\r
- ******************************************************************************/ \r
-\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include "bp.h"\r
-#include "libcds/includes/static_bitsequence.h"\r
-#include "libcds/includes/alphabet_mapper.h"\r
-#include "libcds/includes/static_sequence.h"\r
-\r
-//#include "TextCollection/TextCollection.h"\r
-//using SXSI::TextCollection;\r
-\r
-// this constant is used to efficiently compute the child operation in the tree\r
-#define OPTD 10\r
-\r
-#define NULLT -1\r
-\r
- // sets bit p in e\r
-#define bitset(e,p) ((e)[(p)/W] |= (1<<((p)%W)))\r
- // cleans bit p in e\r
-#define bitclean(e,p) ((e)[(p)/W] &= ~(1<<((p)%W)))\r
-\r
-\r
-typedef int treeNode;\r
-typedef int TagType; \r
-typedef int DocID; \r
-\r
-typedef struct {\r
- int min;\r
- int max;\r
-} range;\r
-\r
-\r
-class XMLTree {\r
- /** Balanced parentheses representation of the tree */\r
- bp *Par;\r
- \r
- /** Mapping from tag identifer to tag name */ \r
- unsigned char **TagName;\r
- \r
- /** boolean flag indicating whether we are indexing empty texts or not */\r
- bool indexing_empty_texts; \r
- \r
- /** Bit vector indicating with a 1 the positions of the non-empty texts. */\r
- static_bitsequence_rrr02 *EBVector; \r
- \r
- /** Tag sequence represented with a data structure for rank and select */\r
- static_sequence_wvtree *Tags;\r
-\r
- /** The texts in the XML document */\r
- //TextCollection *Text;\r
- \r
- /** Flag indicating whether the whole data structure has been constructed or \r
- * not. If the value is true, you cannot add more texts, nodes, etc. */\r
- bool finished;\r
-\r
- /** Flag indicating whether the construction of the data structure has been\r
- * initialized or not (by calling method OpenDocument()). If this is true,\r
- * you cannot insert new tags or texts. */\r
- bool initialized;\r
- \r
- /* the following components are used for construction purposes */\r
- pb *par_aux;\r
- TagType *tags_aux;\r
- int npar;\r
- int ntagnames;\r
- unsigned int *empty_texts_aux;\r
- \r
-public:\r
-\r
- /** Data structure constructor */\r
- XMLTree() {finished = false; initialized = false;}; \r
- \r
- /** Data structure destructor */\r
- ~XMLTree();\r
- \r
- /** root(): returns the tree root. */\r
- treeNode Root();\r
- \r
- /** SubtreeSize(x): the number of nodes (and attributes) in the subtree of \r
- * node x. */\r
- int SubtreeSize(treeNode x);\r
- \r
- /** SubtreeTags(x,tag): the number of occurrences of tag within the subtree \r
- * of node x. */\r
- int SubtreeTags(treeNode x, TagType tag);\r
- \r
- /** IsLeaf(x): returns whether node x is leaf or not. In the succinct \r
- * representation this is just a bit inspection. */\r
- bool IsLeaf(treeNode x);\r
- \r
- /** IsAncestor(x,y): returns whether node x is ancestor of node y. */\r
- bool IsAncestor(treeNode x, treeNode y);\r
- \r
- /** IsChild(x,y): returns whether node x is parent of node y. */\r
- bool IsChild(treeNode x, treeNode y);\r
- \r
- /** NumChildren(x): number of children of node x. Constant time with the \r
- * data structure of Sadakane. */\r
- int NumChildren(treeNode x);\r
- \r
- /** ChildNumber(x): returns i if node x is the i-th children of its \r
- * parent. */\r
- inline int ChildNumber(treeNode x);\r
-\r
- /** Depth(x): depth of node x, a simple binary rank on the parentheses \r
- * sequence. */\r
- int Depth(treeNode x);\r
- \r
- /** Preorder(x): returns the preorder number of node x, just regarding tree \r
- * nodes (and not texts). */ \r
- int Preorder(treeNode x);\r
- \r
- /** Postorder(x): returns the postorder number of node x, just regarding \r
- * tree nodes (and not texts). */\r
- int Postorder(treeNode x);\r
- \r
- /** Tag(x): returns the tag identifier of node x. */\r
- TagType Tag(treeNode x);\r
- \r
- /** DocIds(x): returns the range (i.e., a pair of integers) of document \r
- * identifiers that descend from node x. */\r
- range DocIds(treeNode x);\r
- \r
- /** Parent(x): returns the parent node of node x. */\r
- treeNode Parent(treeNode x);\r
- \r
- /** Child(x,i): returns the i-th child of node x, assuming it exists. */ \r
- treeNode Child(treeNode x, int i);\r
- \r
- /** FirstChild(x): returns the first child of node x, assuming it exists. \r
- * Very fast in BP. */\r
- treeNode FirstChild(treeNode x);\r
- \r
- /** NextSibling(x): returns the next sibling of node x, assuming it \r
- * exists. */\r
- treeNode NextSibling(treeNode x);\r
- \r
- /** PrevSibling(x): returns the previous sibling of node x, assuming it \r
- * exists. */\r
- treeNode PrevSibling(treeNode x);\r
- \r
- /** TaggedChild(x,i,tag): returns the i-th child of node x tagged tag, or \r
- * NULLT if there is none. Because of the balanced-parentheses representation \r
- * of the tree, this operation is not supported efficiently, just iterating \r
- * among the children of node x until finding the desired child. */\r
- treeNode TaggedChild(treeNode x, int i, TagType tag);\r
- \r
- /** TaggedDesc(x,tag): returns the first node tagged tag with larger \r
- * preorder than x and within the subtree of x. Returns NULT if there \r
- * is none. */\r
- treeNode TaggedDesc(treeNode x, TagType tag);\r
-\r
- /** TaggedPrec(x,tag): returns the first node tagged tag with smaller \r
- * preorder than x and not an ancestor of x. Returns NULLT if there \r
- * is none. */\r
- treeNode TaggedPrec(treeNode x, TagType tag);\r
- \r
- /** TaggedFoll(x,tag): returns the first node tagged tag with larger \r
- * preorder than x and not in the subtree of x. Returns NULLT if there \r
- * is none. */\r
- treeNode TaggedFoll(treeNode x, TagType tag);\r
- \r
- /** PrevText(x): returns the document identifier of the text to the left of \r
- * node x, or NULLT if x is the root node. */\r
- DocID PrevText(treeNode x);\r
- \r
- /** NextText(x): returns the document identifier of the text to the right of \r
- * node x, or NULLT if x is the root node. */\r
- DocID NextText(treeNode x);\r
- \r
- /** MyText(x): returns the document identifier of the text below node x, or \r
- * NULLT if x is not a leaf node. */\r
- DocID MyText(treeNode x);\r
- \r
- /** TextXMLId(d): returns the preorder of document with identifier d in the \r
- * tree consisting of all tree nodes and all text nodes. */\r
- int TextXMLId(DocID d);\r
- \r
- /** NodeXMLId(x): returns the preorder of node x in the tree consisting of \r
- * all tree nodes and all text nodes. */\r
- int NodeXMLId(treeNode x);\r
- \r
- /** ParentNode(d): returns the parent node of document identifier d. */\r
- treeNode ParentNode(DocID d);\r
-\r
- /** OpenDocument(empty_texts,sample_rate_text): initilizes the construction\r
- * of the data structure for the XML document. Parameter empty_texts \r
- * indicates whether we index empty texts in document or not. Parameter \r
- * sample_rate_text indicates the sampling rate for the text searching data\r
- * structures (small values get faster searching but a bigger space \r
- * requirement). Returns a non-zero value upon success, NULLT in case of \r
- * error. */\r
- int OpenDocument(bool empty_texts, int sample_rate_text);\r
-\r
- /** CloseDocument(): finishes the construction of the data structure for \r
- * the XML document. Tree and tags are represented in the final form, \r
- * dynamic data structures are made static, and the flag "finished" is set \r
- * to true. After that, the data structure can be queried. */\r
- int CloseDocument();\r
-\r
- /** NewOpenTag(tagname): indicates the event of finding a new opening tag \r
- * in the document. Tag name is given. Returns a non-zero value upon \r
- * success, and returns NULLT in case of error. */\r
- int NewOpenTag(unsigned char *tagname);\r
- \r
- /** NewClosingTag(tagname): indicates the event of finding a new closing tag\r
- * in the document. Tag name is given. Returns a non-zero value upon \r
- * success, and returns NULLT in case of error. */\r
- int NewClosingTag(unsigned char *tagname);\r
- \r
- /** NewText(s): indicates the event of finding a new (non-empty) text s in \r
- * the document. The new text is inserted within the text collection. \r
- * Returns a non-zero value upon success, NULLT in case of error. */\r
- int NewText(unsigned char *s);\r
-\r
- /** NewEmptyText(): indicates the event of finding a new empty text in the \r
- * document. In case of indexing empty and non-empty texts, we insert the \r
- * empty texts into the text collection. In case of indexing only non-empty\r
- * texts, it just indicates an empty text in the bit vector of empty texts. \r
- * Returns a non-zero value upon success, NULLT in case of error. */\r
- int NewEmptyText();\r
-\r
- /** GetTagId(tagname): returns the tag identifier corresponding to a given \r
- * tag name. Returns NULLT in case that the tag name does not exists. */\r
- TagType GetTagId(unsigned char *tagname);\r
-\r
- /** GetTagName(tagid): returns the tag name of a given tag identifier. \r
- * Returns NULL in case that the tag identifier is not valid.*/\r
- unsigned char *GetTagName(TagType tagid);\r
-\r
- /** saveXMLTree: saves XML tree data structure to file. Every component of \r
- * the collection is stored in different files (same name, different file \r
- * extensions). */\r
- void Save(unsigned char *filename);\r
- \r
- /** load: loads XML tree data structure from file. */\r
- static XMLTree *Load(unsigned char *filename, int sample_rate_text); \r
-};\r
-\r
-\r
+/******************************************************************************
+ * Copyright (C) 2008 by Diego Arroyuelo *
+ * Interface for the in-memory XQuery/XPath engine *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License as published *
+ * by the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ******************************************************************************/
+
+#ifndef XMLTREE_H_
+#define XMLTREE_H_
+
+
+#include <unordered_set>
+#include <unordered_map>
+#include <sstream>
+#include <TextCollection/TextCollectionBuilder.h>
+
+#undef W
+#undef WW
+#undef Wminusone
+
+#include <bp/bp.h>
+#include <libcds/includes/basics.h>
+#include <libcds/includes/static_bitsequence.h>
+#include <libcds/includes/alphabet_mapper.h>
+#include <libcds/includes/static_sequence.h>
+
+using SXSI::TextCollection;
+using SXSI::TextCollectionBuilder;
+
+
+// this constant is used to efficiently compute the child operation in the tree
+#define OPTD 10
+
+#define NULLT -1
+
+#define PERM_SAMPLE 10
+
+
+typedef int treeNode;
+typedef int TagType;
+typedef int DocID;
+
+typedef struct {
+ int min;
+ int max;
+} range;
+
+// Encoding of the XML Document :
+// The following TAGs and IDs are fixed, "" is the tag of the root.
+// a TextNode is represented by a leaf <<$>></<$>> The DocId in the TextCollection
+// of that leaf is kept in a bit sequence.
+// a TextNode below an attribute is likewise represented by a leaf <<@$>><</@$>>
+// An element <e a1="v1" a2="v2" ... an="vn" > ...</e> the representation is:
+// <e><<@>> <<@>a1> <<$@>>DocID(v1)</<$@>></<@>a1> ... </<@>> .... </e>
+// Hence the attributes (if any) are always below the first child of their element,
+// as the children of a fake node <@>.
+
+
+#define DOCUMENT_OPEN_TAG ""
+#define DOCUMENT_TAG_ID 0
+#define ATTRIBUTE_OPEN_TAG "<@>"
+#define ATTRIBUTE_TAG_ID 1
+#define PCDATA_OPEN_TAG "<$>"
+#define PCDATA_TAG_ID 2
+#define ATTRIBUTE_DATA_OPEN_TAG "<@$>"
+#define ATTRIBUTE_DATA_TAG_ID 3
+#define CLOSING_TAG "</>"
+#define CLOSING_TAG_ID 4
+#define DOCUMENT_CLOSE_TAG "/"
+#define ATTRIBUTE_CLOSE_TAG "/<@>"
+#define PCDATA_CLOSE_TAG "/<$>"
+#define ATTRIBUTE_DATA_CLOSE_TAG "/<@$>"
+
+
+typedef std::unordered_set<int> TagIdSet;
+typedef std::unordered_map<std::string,int> TagIdMap;
+typedef TagIdMap::const_iterator TagIdMapIT;
+
+#define REGISTER_TAG(v,h,t) do { (h)->insert(std::make_pair((t),(v)->size()));\
+ (v)->push_back(t); } while (false)
+
+// returns NULLT if the test is true
+#define NULLT_IF(x) do { if (x) return NULLT; } while (0)
+
+// Direct calls to sarray library
+
+#define BUFFER_ALLOC (8192 * 2)
+#define BUFFER_SIZE (BUFFER_ALLOC / 2)
+
+// tag position -> tree node
+static treeNode tagpos2node(int t)
+ {
+ return (treeNode) t;
+ }
+// tree node -> tag position
+static int node2tagpos(treeNode x)
+{
+ return (int)x;
+}
+
+
+class XMLTreeBuilder;
+
+class XMLTree {
+
+ // Only the builder can access the constructor
+ friend class XMLTreeBuilder;
+
+ private:
+ /** Balanced parentheses representation of the tree */
+ bp *Par;
+
+ /** Mapping from tag identifer to tag name */
+ std::vector<std::string> *TagName;
+ TagIdMap * tIdMap;
+
+ /** Bit vector indicating with a 1 the positions of the non-empty texts. */
+ static_bitsequence *EBVector;
+
+ /** Tag sequence represented with a data structure for rank and select */
+ static_sequence *Tags;
+ uint * tags_fix;
+ uint tags_blen, tags_len;
+
+ /** The texts in the XML document */
+ TextCollection *Text;
+
+ // Allows to disable the TextCollection for benchmarkin purposes
+ bool disable_tc;
+ SXSI::TextCollectionBuilder::index_type_t text_index_type;
+
+ std::string *buffer;
+ std::vector<std::string *> *print_stack;
+
+
+ void _real_flush(int fd, size_t size) {
+ if (size == 0) return;
+ size_t written;
+ while (1) {
+ written = write(fd, buffer->data(), size);
+ if ((written < 0) && (errno == EAGAIN || errno == EINTR))
+ continue;
+ break;
+ };
+ buffer->clear();
+
+ }
+
+ void _flush(int fd){
+ size_t size = buffer->size();
+ if (size < BUFFER_SIZE) return;
+ _real_flush(fd, size);
+ }
+
+ void _dput_str(std::string s, int fd){
+ buffer->append(s);
+ _flush(fd);
+ }
+
+ void _dputs(const char* s, int fd){
+ buffer->append(s);
+ _flush(fd);
+ }
+
+ void _dputc(const char c, int fd){
+ buffer->push_back(c);
+ }
+
+ size_t _dprintf(const char* s, int fd){
+ if (s == NULL) return 0;
+ size_t i;
+ char c;
+ for (i = 0; (c = s[i]); i++) {
+ switch (c) {
+ case '"':
+ _dputs(""", fd);
+ break;
+ case '&':
+ _dputs("&", fd);
+ break;
+ case '\'':
+ _dputs("'", fd);
+ break;
+ case '<':
+ _dputs("<", fd);
+ break;
+ case '>':
+ _dputs(">", fd);
+ break;
+ default:
+ _dputc(c, fd);
+
+ };
+ };
+ return i;
+ }
+
+ void PrintNode(treeNode n, int fd);
+ /** Data structure constructors */
+ XMLTree(){ buffer = 0;};
+
+ // non const pointer are freed by this method.
+ XMLTree( pb * const par,
+ uint npar,
+ std::vector<std::string> * const TN,
+ TagIdMap * const tim, uint *empty_texts_bmp,
+ TagType *tags,
+ TextCollection * const TC, bool dis_tc,
+ TextCollectionBuilder::index_type_t _index_type );
+
+public:
+ /** Data structure destructor */
+ ~XMLTree();
+
+ /** root(): returns the tree root. */
+ treeNode Root() { return 0; }
+
+ /** Size() : Number of parenthesis */
+ unsigned int Size(){
+ return tags_len/2;
+ }
+
+
+ /** NumTags() : Number of distinct tags */
+ unsigned int NumTags() {
+ return TagName->size();
+ }
+
+ int TagsBinaryLength(){ return tags_blen; };
+ unsigned int TagStructLength(){ return uint_len(tags_blen,tags_len); };
+ unsigned int * TagStruct() { return tags_fix; };
+
+
+ /** SubtreeSize(x): the number of nodes (and attributes) in the subtree of
+ * node x. */
+ int SubtreeSize(treeNode x) { return bp_subtree_size(Par, x); }
+
+ /** SubtreeTags(x,tag): the number of occurrences of tag within the subtree
+ * of node x. */
+ int SubtreeTags(treeNode x, TagType tag){
+ //int s = x + 2*subtree_size(Par, x) - 1;
+ treeNode y = bp_find_close(Par, x);
+
+ if (y - x < 10) {
+ int count = 0;
+ for(int i = x; i < y; i++)
+ count += (Tag(i) == tag);
+ return count;
+ }
+ else
+ return (Tags->rank(tag, y) - Tags->rank(tag, x));
+ };
+
+ /** SubtreeElements(x) of element nodes in the subtree of x
+ */
+ int SubtreeElements(treeNode x);
+
+ /** IsLeaf(x): returns whether node x is leaf or not. In the succinct
+ * representation this is just a bit inspection. */
+
+ bool IsLeaf(treeNode x);
+
+ /** IsAncestor(x,y): returns whether node x is ancestor of node y. */
+
+ bool IsAncestor(treeNode x, treeNode y);
+
+
+ /** IsRigthDescendant returns true if y is a descendant of x and y is
+ not a descendant of the first child of x */
+ bool IsRightDescendant(treeNode x, treeNode y) {
+ if (x <= Root()) return false;
+ treeNode z = bp_parent_close(Par, x);
+ treeNode c = bp_find_close(Par, x);
+ return (y > c && y < z );
+ }
+
+
+ /** IsChild(x,y): returns whether node x is parent of node y. */
+ bool IsChild(treeNode x, treeNode y);
+
+ /** IsFirstChild(x): returns whether node x is the first child of its parent. */
+ /* OCAML */
+ bool IsFirstChild(treeNode x) {
+ return ((x != NULLT)&&(x==Root() || bp_prev_sibling(Par,x) == (treeNode)-1));
+ };
+
+ /** NumChildren(x): number of children of node x. Constant time with the
+ * data structure of Sadakane. */
+ int NumChildren(treeNode x);
+
+ /** ChildNumber(x): returns i if node x is the i-th children of its
+ * parent. */
+ int ChildNumber(treeNode x);
+
+ /** Depth(x): depth of node x, a simple binary rank on the parentheses
+ * sequence. */
+ int Depth(treeNode x);
+
+ /** Preorder(x): returns the preorder number of node x, just regarding tree
+ * nodes (and not texts). */
+ int Preorder(treeNode x);
+
+ /** Postorder(x): returns the postorder number of node x, just regarding
+ * tree nodes (and not texts). */
+ int Postorder(treeNode x);
+
+
+ /** DocIds(x): returns the range (i.e., a pair of integers) of document
+ * identifiers that descend from node x. */
+ range DocIds(treeNode x);
+
+ /** Parent(x): returns the parent node of node x. */
+ treeNode Parent(treeNode x) {
+ return (x == Root()) ? NULLT : bp_parent(Par, x);
+ };
+
+ treeNode BinaryParent(treeNode x){
+ if (x <= Root())
+ return NULLT;
+ else {
+ treeNode prev = x - 1;
+ return (bp_inspect(Par, prev) == OP) ? prev : bp_find_open(Par, prev);
+ };
+ };
+
+ /* Assumes x is neither 0 nor -1 */
+
+ /** Child(x,i): returns the i-th child of node x, assuming it exists. */
+ treeNode Child(treeNode x, int i);
+
+
+
+ /** LastChild(x): returns the last child of node x. */
+ treeNode LastChild(treeNode x) {
+ NULLT_IF(x == NULLT || bp_isleaf(Par,x));
+ return bp_find_open(Par, bp_find_close(Par, x)-1);
+ }
+
+ /** PrevSibling(x): returns the previous sibling of node x, assuming it
+ * exists. */
+
+ treeNode PrevSibling(treeNode x)
+ {
+ NULLT_IF(x==NULLT);
+ return bp_prev_sibling(Par, x);
+ }
+
+
+ /** TaggedChild(x,tag): returns the first child of node x tagged tag, or
+ * NULLT if there is none. Because of the balanced-parentheses representation
+ * of the tree, this operation is not supported efficiently, just iterating
+ * among the children of node x until finding the desired child. */
+
+
+ treeNode SelectChild(treeNode x, TagIdSet * tags);
+
+ /** TaggedFollowingSibling(x,tag): returns the first sibling of node x tagged tag, or
+ * NULLT if there is none. */
+
+ treeNode SelectFollowingSibling(treeNode x, TagIdSet * tags);
+
+
+
+
+ treeNode SelectDescendant(treeNode x, TagIdSet * tags) {
+ NULLT_IF (x == NULLT);
+ treeNode fc = x+1;
+ if (bp_inspect(Par, fc) == CP) return NULLT;
+ treeNode min = NULLT;
+ treeNode aux;
+
+ TagIdSet::const_iterator tagit;
+ for (tagit = tags->begin(); tagit != tags->end(); ++tagit) {
+ aux = TaggedDescendant(x, (TagType) *tagit);
+ if (((unsigned int) aux) < ((unsigned int) min)) min = aux;
+ };
+ return min;
+ }
+
+ /** TaggedPrec(x,tag): returns the first node tagged tag with smaller
+ * preorder than x and not an ancestor of x. Returns NULLT if there
+ * is none. */
+ treeNode TaggedPreceding(treeNode x, TagType tag);
+
+ /** TaggedFoll(x,tag): returns the first node tagged tag with larger
+ * preorder than x and not in the subtree of x. Returns NULLT if there
+ * is none. */
+ treeNode TaggedFollowing(treeNode x, TagType tag);
+
+
+
+ treeNode SelectFollowingBelow(treeNode x, TagIdSet * tags, treeNode ancestor);
+
+ // treeNode TaggedFollowingBefore(treeNode x, TagType tag,treeNode closing);
+
+ treeNode SelectFollowingBefore(treeNode x, TagIdSet * tags, treeNode ancestor_closing)
+ {
+
+ NULLT_IF(x <= 0);
+
+ treeNode close = bp_find_close(Par,x);
+
+
+ treeNode min = NULLT;
+ treeNode aux;
+
+
+ TagIdSet::const_iterator tagit;
+ for (tagit = tags->begin(); tagit != tags->end(); ++tagit) {
+
+ aux = tagpos2node(Tags->select_next(*tagit, close));
+
+ if (((unsigned int) aux) < ((unsigned int) min)) min = aux;
+ };
+
+
+ return (min < ancestor_closing) ? min : NULLT;
+
+ }
+
+ /** TaggedAncestor(x, tag): returns the closest ancestor of x tagged
+ * tag. Return NULLT is there is none. */
+ treeNode TaggedAncestor(treeNode x, TagType tag);
+
+ /** PrevText(x): returns the document identifier of the text to the left of
+ * node x, or NULLT if x is the root node. */
+ DocID PrevText(treeNode x);
+
+ /** NextText(x): returns the document identifier of the text to the right of
+ * node x, or NULLT if x is the root node. */
+ DocID NextText(treeNode x);
+
+ /** MyText(x): returns the document identifier of the text below node x, or
+ * NULLT if x is not a leaf node. */
+ DocID MyText(treeNode x);
+ DocID MyTextUnsafe(treeNode x);
+
+ /** TextXMLId(d): returns the preorder of document with identifier d in the
+ * tree consisting of all tree nodes and all text nodes. */
+ int TextXMLId(DocID d);
+
+ /** NodeXMLId(x): returns the preorder of node x in the tree consisting of
+ * all tree nodes and all text nodes. */
+ int NodeXMLId(treeNode x);
+
+ /** ParentNode(d): returns the parent node of document identifier d. */
+ treeNode ParentNode(DocID d);
+
+ treeNode PrevNode(DocID d);
+
+ /** GetTagId(tagname): returns the tag identifier corresponding to a given
+ * tag name. Returns NULLT in case that the tag name does not exists. */
+ TagType GetTagId(unsigned char *tagname);
+
+ /** GetTagName(tagid): returns the tag name of a given tag identifier.
+ * Returns NULL in case that the tag identifier is not valid.*/
+ unsigned char *GetTagName(TagType tagid);
+
+ /** GetTagName(tagid): returns the tag name of a given tag identifier.
+ * The result is just a reference and should not be freed by the caller.
+ */
+ const unsigned char *GetTagNameByRef(TagType tagid);
+
+ /** RegisterTag adds a new tag to the tag collection this is needed
+ * if the query contains a tag which is not in the document, we need
+ * to give this new tag a fresh id and store it somewhere. A logical
+ * choice is here.
+ * We might want to use a hashtable instead of an array though.
+ */
+ TagType RegisterTag(unsigned char *tagname);
+
+ bool EmptyText(DocID i) {
+ return Text->EmptyText(i);
+ }
+
+ /** Prefix(s): search for texts prefixed by string s. */
+ TextCollection::document_result Prefix(uchar const *s) {
+ return Text->Prefix(s);
+ }
+
+ /** Suffix(s): search for texts having string s as a suffix. */
+ TextCollection::document_result Suffix(uchar const *s) {
+ return Text->Suffix(s);
+ }
+
+ /** Equal(s): search for texts equal to string s. */
+ TextCollection::document_result Equals(uchar const *s) {
+ return Text->Equal(s);
+ }
+
+ /** Contains(s): search for texts containing string s. */
+ TextCollection::document_result Contains(uchar const *s) {
+ return Text->Contains(s);
+ }
+
+ /** LessThan(s): returns document identifiers for the texts that
+ * are lexicographically smaller than string s. */
+ TextCollection::document_result LessThan(uchar const *s) {
+ return Text->LessThan(s);
+ }
+
+ /** IsPrefix(x): returns true if there is a text prefixed by string s. */
+ bool IsPrefix(uchar const *s) {
+ return Text->IsPrefix(s);
+ }
+
+ /** IsSuffix(s): returns true if there is a text having string s as a
+ * suffix.*/
+ bool IsSuffix(uchar const *s) {
+ return Text->IsSuffix(s);
+ }
+
+ /** IsEqual(s): returns true if there is a text that equals given
+ * string s. */
+ bool IsEqual(uchar const *s) {
+ return Text->IsEqual(s);
+ }
+
+ /** IsContains(s): returns true if there is a text containing string s. */
+ bool IsContains(uchar const *s) {
+ return Text->IsContains(s);
+ }
+
+ /** IsLessThan(s): returns true if there is at least a text that is
+ * lexicographically smaller than string s. */
+ bool IsLessThan(uchar const *s) {
+ return Text->IsLessThan(s);
+ }
+
+ /** Count(s): Global counting */
+ unsigned Count(uchar const *s) {
+ return Text->Count(s);
+ }
+
+ /** CountPrefix(s): counting version of Prefix(s). */
+ unsigned CountPrefix(uchar const *s) {
+ return Text->CountPrefix(s);
+ }
+
+ /** CountSuffix(s): counting version of Suffix(s). */
+ unsigned CountSuffix(uchar const *s) {
+ return Text->CountSuffix(s);
+ }
+
+ /** CountEqual(s): counting version of Equal(s). */
+ unsigned CountEqual(uchar const *s) {
+ return Text->CountEqual(s);
+ }
+
+ /** CountContains(s): counting version of Contains(s). */
+ unsigned CountContains(uchar const *s) {
+ return Text->CountContains(s);
+ }
+
+ /** CountLessThan(s): counting version of LessThan(s). */
+ unsigned CountLessThan(uchar const *s) {
+ return Text->CountLessThan(s);
+ }
+
+ /** GetText(d): returns the text corresponding to document with
+ * id d. */
+ uchar* GetText(DocID d) {
+
+ uchar * s = Text->GetText(d);
+ return (s[0] == 1 ? (s+1) : s);
+ }
+
+ /** GetText(i, j): returns the texts corresponding to documents with
+ * ids i, i+1, ..., j. Texts are separated by '\0' character. */
+ // uchar* GetText(DocID i, DocID j) {
+ // uchar * s = Text->GetText(i, j);
+ // return (s[0] == 1 ? (uchar*)"" : s);
+ //}
+
+ TextCollection *getTextCollection() {
+ return Text;
+ }
+
+ /** Save: saves XML tree data structure to file. */
+ void Save(int fd, char* name );
+
+ /** Load: loads XML tree data structure from file. sample_rate_text
+ * indicates the sample rate for the text search data structure. */
+ static XMLTree *Load(int fd, bool load_tc, int sample_factor, char * name);
+
+ void insertTag(TagType tag, uint position);
+
+ void print_stats();
+
+
+ /** Parenthesis functions */
+ treeNode Closing(treeNode x);
+
+ bool IsOpen(treeNode x);
+
+
+ /** Print procedure */
+ void Print(int fd,treeNode x, bool no_text);
+ void Print(int fd,treeNode x) { Print(fd,x,false); }
+ void Flush(int fd){ if (buffer) _real_flush(fd, buffer->size()); }
+
+ // The following are inlined here for speed
+ /** Tag(x): returns the tag identifier of node x. */
+
+ inline TagType Tag(treeNode x) const throw () {
+ if (tags_blen == 8)
+ return (TagType) (((uchar*)tags_fix)[(int) x]);
+ else
+ return get_field(tags_fix, tags_blen, x);
+ /*
+ {
+ size_t idxlen = x * tags_blen;
+ size_t j = idxlen % W;
+ size_t i = idxlen / W;
+ size_t offset = W - tags_blen;
+ size_t offset2 = offset - j;
+ size_t w = tags_fix[i];
+ return (offset2 >= 0)
+ ? ( w << offset2 ) >> offset
+ : ( w >> j) | (tags_fix[i+1] << (W+offset2)) >> offset;
+ }; */
+
+ }
+
+ /** FirstChild(x): returns the first child of node x, or NULLT if the node is a leaf
+ */
+ treeNode FirstChild(treeNode x) {
+ NULLT_IF(x==NULLT);
+ return bp_first_child(Par, x);
+ };
+
+
+ /** FirstElement(x): returns the first non text, non attribute child of node x, or NULLT
+ * if none.
+ */
+ treeNode FirstElement(treeNode node){
+ {
+ NULLT_IF(node == NULLT);
+ treeNode x = bp_first_child(Par, node);
+ NULLT_IF(x == NULLT);
+ switch (Tag(x)){
+
+ case ATTRIBUTE_TAG_ID:
+ x = bp_next_sibling(Par,x);
+ if (x == NULLT || Tag(x) != PCDATA_TAG_ID) return x;
+
+ case PCDATA_TAG_ID:
+ x = x+2;
+ return (bp_inspect(Par,x)==OP)? x : NULLT;
+
+ default:
+ return x;
+ }
+ }
+ };
+
+ /** NextSibling(x): returns the next sibling of node x, or NULLT if none
+ * exists. */
+
+ treeNode NextSibling(treeNode x) {
+ NULLT_IF (x <= 0);
+ return bp_next_sibling(Par, x);
+ };
+
+ /** NextElement(x): returns the first non text, non attribute sibling of node x, or NULLT
+ * if none.
+ */
+ treeNode NextElement(treeNode x)
+ {
+ NULLT_IF(x <= 0);
+ x = bp_next_sibling(Par, x);
+ NULLT_IF(x == NULLT);
+ if (Tag(x) == PCDATA_TAG_ID){
+ int y = x+2;
+ return (bp_inspect(Par, y) == OP) ? y : NULLT;
+ }
+ else return x;
+ };
+ /** TaggedDesc(x,tag): returns the first node tagged tag with larger
+ * preorder than x and within the subtree of x. Returns NULT if there
+ * is none. */
+ inline treeNode TaggedNext(treeNode x, TagType tag)
+ {
+ return tagpos2node(Tags->select_next(tag,node2tagpos(x)));
+ }
+ inline treeNode TaggedDescendant(treeNode x, TagType tag)
+ {
+
+ int s = (int) Tags->select_next(tag,node2tagpos(x));
+ NULLT_IF (s == -1);
+
+ treeNode y = tagpos2node(s); // transforms the tag position into a node position
+
+ return (bp_is_ancestor(Par,x,y) ? y : NULLT);
+ };
+
+ inline treeNode TaggedFollowingBelow(treeNode x, TagType tag, treeNode ancestor)
+ {
+ treeNode close = bp_find_close(Par, x);
+ treeNode s = tagpos2node(Tags->select_next(tag, close));
+
+ if (ancestor == Root() || s == NULLT || s < bp_find_close(Par,ancestor)) return s;
+ else return NULLT;
+ };
+
+ inline treeNode TaggedFollowingBefore(treeNode x, TagType tag, treeNode ancestor_closing)
+ {
+ treeNode close = bp_find_close(Par, x);
+ treeNode s = tagpos2node(Tags->select_next(tag, close));
+
+ if (ancestor_closing == Root() || s == NULLT || s < ancestor_closing) return s;
+ else return NULLT;
+ };
+
+ inline treeNode NextNodeBefore(treeNode x, treeNode ancestor_closing)
+ {
+ treeNode close = bp_find_close(Par, x);
+ int rank = bp_rank_open(Par, close);
+ treeNode y = bp_select_open(Par, rank+1);
+ return (y < ancestor_closing) ? y : NULLT;
+ };
+
+// TaggedSibling(x,tag): returns the first sibling of node x tagged tag, or NULLT if there is none.
+treeNode TaggedFollowingSibling(treeNode x, TagType tag)
+{
+ NULLT_IF(x==NULLT);
+ treeNode sibling = x;
+ TagType ctag;
+ while ((sibling = bp_next_sibling(Par, sibling)) != NULLT) {
+ ctag = Tag(sibling);
+ if (ctag == tag) return sibling;
+ }
+ return NULLT;
+};
+
+treeNode TaggedChild(treeNode x, TagType tag)
+{
+
+ NULLT_IF(x==NULLT || bp_isleaf(Par,x));
+ treeNode child;
+ child = bp_first_child(Par, x);
+
+if (Tag(child) == tag)
+ return child;
+ else
+ return TaggedFollowingSibling(child, tag);
+};
+
+
+};
+
+
+#endif
+