-\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
-#ifndef XMLTREE_H_\r
-#define XMLTREE_H_\r
-#include <unordered_set>\r
-#include <unordered_map>\r
-#include "TextCollection/TextCollectionBuilder.h"\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <cstring>\r
-\r
-\r
-#undef W\r
-#undef WW\r
-#undef Wminusone\r
-\r
-#include "bp.h"\r
-\r
-#include <static_bitsequence.h>\r
-#include <alphabet_mapper.h>\r
-#include <static_sequence.h>\r
-using SXSI::TextCollection;\r
-using SXSI::TextCollectionBuilder;\r
-\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
-#define PERM_SAMPLE 10\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
-// Encoding of the XML Document :\r
-// The following TAGs and IDs are fixed, "" is the tag of the root.\r
-// a TextNode is represented by a leaf <<$>></<$>> The DocId in the TextCollection\r
-// of that leaf is kept in a bit sequence.\r
-// a TextNode below an attribute is likewise represented by a leaf <<@$>><</@$>>\r
-// An element <e a1="v1" a2="v2" ... an="vn" > ...</e> the representation is:\r
-// <e><<@>> <<@>a1> <<$@>>DocID(v1)</<$@>></<@>a1> ... </<@>> .... </e>\r
-// Hence the attributes (if any) are always below the first child of their element,\r
-// as the children of a fake node <@>.\r
-\r
-\r
-#define DOCUMENT_OPEN_TAG ""\r
-#define DOCUMENT_TAG_ID 0\r
-#define ATTRIBUTE_OPEN_TAG "<@>"\r
-#define ATTRIBUTE_TAG_ID 1\r
-#define PCDATA_OPEN_TAG "<$>"\r
-#define PCDATA_TAG_ID 2\r
-#define ATTRIBUTE_DATA_OPEN_TAG "<@$>"\r
-#define ATTRIBUTE_DATA_TAG_ID 3\r
-#define DOCUMENT_CLOSE_TAG "/"\r
-#define ATTRIBUTE_CLOSE_TAG "/<@>"\r
-#define PCDATA_CLOSE_TAG "/<$>"\r
-#define ATTRIBUTE_DATA_CLOSE_TAG "/<@$>"\r
-\r
-\r
-\r
-typedef std::unordered_map<string,int> TagIdMap;\r
-typedef TagIdMap::const_iterator TagIdMapIT;\r
-\r
-#define REGISTER_TAG(v,h,t) do { (h)->insert(std::make_pair((t),(v)->size()));\\r
- (v)->push_back(t); } while (false)\r
-\r
-\r
-class XMLTreeBuilder;\r
-\r
-class XMLTree {\r
-\r
- // Only the builder can access the constructor\r
- friend class XMLTreeBuilder;\r
-\r
- private:\r
- /** Balanced parentheses representation of the tree */\r
- bp *Par;\r
- \r
- /** Mapping from tag identifer to tag name */ \r
- vector<string> *TagName;\r
- TagIdMap * tIdMap;\r
- \r
- /** Bit vector indicating with a 1 the positions of the non-empty texts. */\r
- static_bitsequence *EBVector; \r
- \r
- /** Tag sequence represented with a data structure for rank and select */\r
- static_sequence *Tags;\r
- uint * tags_fix;\r
- uint tags_blen, tags_len;\r
-\r
- /** The texts in the XML document */\r
- TextCollection *Text;\r
-\r
- /** The texts in the XML document (cached for faster display) */\r
- vector<string> *CachedText;\r
-\r
- // Allows to disable the TextCollection for benchmarkin purposes\r
- bool disable_tc;\r
- \r
-\r
- /** Data structure constructors */\r
- XMLTree(){;};\r
-\r
- // non const pointer are freed by this method.\r
- XMLTree( pb * const par, uint npar, vector<string> * const TN, TagIdMap * const tim, uint *empty_texts_bmp, TagType *tags,\r
- TextCollection * const TC, vector<string> * const CT, bool dis_tc);\r
-\r
-public: \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
- /** IsFirstChild(x): returns whether node x is the first child of its parent. */\r
- bool IsFirstChild(treeNode x);\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
- treeNode FirstElement(treeNode x);\r
-\r
- /** LastChild(x): returns the last child of node x. */\r
- treeNode LastChild(treeNode x);\r
- \r
- /** NextSibling(x): returns the next sibling of node x, assuming it \r
- * exists. */\r
- treeNode NextSibling(treeNode x);\r
- treeNode NextElement(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,tag): returns the first 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, TagType tag);\r
- \r
- treeNode SelectChild(treeNode x, std::unordered_set<int> * tags);\r
-\r
- /** TaggedFollSibling(x,tag): returns the first sibling of node x tagged tag, or \r
- * NULLT if there is none. */\r
- treeNode TaggedFollSibling(treeNode x, TagType tag);\r
- \r
- treeNode SelectFollSibling(treeNode x, std::unordered_set<int> * tags);\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
- treeNode SelectDesc(treeNode x, std::unordered_set<int> * tags);\r
-\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
- treeNode TaggedFollBelow(treeNode x, TagType tag,treeNode root); \r
- \r
- treeNode SelectFollBelow(treeNode x, std::unordered_set<int> * tags, treeNode root);\r
-\r
- /** TaggedFollowingSibling(x,tag) */\r
- treeNode TaggedFollowingSibling(treeNode x, TagType tag);\r
-\r
- /** TaggedAncestor(x, tag): returns the closest ancestor of x tagged \r
- * tag. Return NULLT is there is none. */\r
- treeNode TaggedAncestor(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
- treeNode PrevNode(DocID d);\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
- /** GetTagName(tagid): returns the tag name of a given tag identifier. \r
- * The result is just a reference and should not be freed by the caller.\r
- */\r
- const unsigned char *GetTagNameByRef(TagType tagid);\r
-\r
- /** RegisterTag adds a new tag to the tag collection this is needed\r
- * if the query contains a tag which is not in the document, we need\r
- * to give this new tag a fresh id and store it somewhere. A logical\r
- * choice is here.\r
- * We might want to use a hashtable instead of an array though.\r
- */\r
- TagType RegisterTag(unsigned char *tagname);\r
-\r
- bool EmptyText(DocID i) {\r
- return Text->EmptyText(i);\r
- }\r
-\r
- /** Prefix(s): search for texts prefixed by string s. */\r
- TextCollection::document_result Prefix(uchar const *s) {\r
- return Text->Prefix(s);\r
- }\r
-\r
- /** Suffix(s): search for texts having string s as a suffix. */\r
- TextCollection::document_result Suffix(uchar const *s) {\r
- return Text->Suffix(s);\r
- }\r
-\r
- /** Equal(s): search for texts equal to string s. */\r
- TextCollection::document_result Equal(uchar const *s) {\r
- return Text->Equal(s);\r
- }\r
-\r
- /** Contains(s): search for texts containing string s. */\r
- TextCollection::document_result Contains(uchar const *s) {\r
- return Text->Contains(s);\r
- }\r
-\r
- /** LessThan(s): returns document identifiers for the texts that\r
- * are lexicographically smaller than string s. */\r
- TextCollection::document_result LessThan(uchar const *s) {\r
- return Text->LessThan(s);\r
- }\r
- \r
- /** IsPrefix(x): returns true if there is a text prefixed by string s. */\r
- bool IsPrefix(uchar const *s) {\r
- return Text->IsPrefix(s);\r
- } \r
- \r
- /** IsSuffix(s): returns true if there is a text having string s as a \r
- * suffix.*/\r
- bool IsSuffix(uchar const *s) {\r
- return Text->IsSuffix(s);\r
- }\r
- \r
- /** IsEqual(s): returns true if there is a text that equals given \r
- * string s. */\r
- bool IsEqual(uchar const *s) {\r
- return Text->IsEqual(s);\r
- }\r
- \r
- /** IsContains(s): returns true if there is a text containing string s. */\r
- bool IsContains(uchar const *s) {\r
- return Text->IsContains(s);\r
- }\r
- \r
- /** IsLessThan(s): returns true if there is at least a text that is \r
- * lexicographically smaller than string s. */\r
- bool IsLessThan(uchar const *s) {\r
- return Text->IsLessThan(s);\r
- }\r
- \r
- /** Count(s): Global counting */\r
- unsigned Count(uchar const *s) {\r
- return Text->Count(s);\r
- }\r
-\r
- /** CountPrefix(s): counting version of Prefix(s). */\r
- unsigned CountPrefix(uchar const *s) {\r
- return Text->CountPrefix(s);\r
- }\r
- \r
- /** CountSuffix(s): counting version of Suffix(s). */\r
- unsigned CountSuffix(uchar const *s) {\r
- return Text->CountSuffix(s);\r
- }\r
- \r
- /** CountEqual(s): counting version of Equal(s). */\r
- unsigned CountEqual(uchar const *s) {\r
- return Text->CountEqual(s);\r
- }\r
- \r
- /** CountContains(s): counting version of Contains(s). */\r
- unsigned CountContains(uchar const *s) {\r
- return Text->CountContains(s);\r
- }\r
- \r
- /** CountLessThan(s): counting version of LessThan(s). */\r
- unsigned CountLessThan(uchar const *s) {\r
- return Text->CountLessThan(s);\r
- }\r
- \r
- /** GetText(d): returns the text corresponding to document with\r
- * id d. */\r
- uchar* GetText(DocID d) {\r
- uchar * s = Text->GetText(d);\r
- return (s[0] == 1 ? (uchar*)"" : s);\r
- }\r
-\r
- /** GetText(i, j): returns the texts corresponding to documents with\r
- * ids i, i+1, ..., j. Texts are separated by '\0' character. */\r
- uchar* GetText(DocID i, DocID j) {\r
- uchar * s = Text->GetText(i, j);\r
- return (s[0] == 1 ? (uchar*)"" : s);\r
- }\r
-\r
- uchar* GetCachedText(DocID d) {\r
- uchar * str = (uchar*) calloc(sizeof(char),(CachedText->at(d).size() + 1));\r
- strcpy((char*) str,(const char*) CachedText->at(d).c_str());\r
- return (uchar*) (str);\r
- }\r
- \r
- TextCollection *getTextCollection() {\r
- return Text;\r
- }\r
- \r
- /** Save: saves XML tree data structure to file. */\r
- void Save(int fd);\r
- \r
- /** Load: loads XML tree data structure from file. sample_rate_text \r
- * indicates the sample rate for the text search data structure. */\r
- static XMLTree *Load(int fd); \r
-\r
- void insertTag(TagType tag, uint position);\r
- \r
- void print_stats();\r
-};\r
-#endif\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 <bp/bp-darray.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)
+#define IS_NIL(x) ((x) < 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,
+ TextCollectionBuilder * const TCB, 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
+