LCOV - code coverage report
Current view: top level - include/xapian - query.h (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core fcfb185a9dd5 Lines: 102 102 100.0 %
Date: 2019-04-18 16:33:14 Functions: 43 45 95.6 %
Branches: 99 159 62.3 %

           Branch data     Line data    Source code
       1                 :            : /** @file query.h
       2                 :            :  * @brief Xapian::Query API class
       3                 :            :  */
       4                 :            : /* Copyright (C) 2011,2012,2013,2014,2015,2016,2017,2018,2019 Olly Betts
       5                 :            :  * Copyright (C) 2008 Richard Boulton
       6                 :            :  *
       7                 :            :  * This program is free software; you can redistribute it and/or
       8                 :            :  * modify it under the terms of the GNU General Public License as
       9                 :            :  * published by the Free Software Foundation; either version 2 of the
      10                 :            :  * License, or (at your option) any later version.
      11                 :            :  *
      12                 :            :  * This program is distributed in the hope that it will be useful,
      13                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15                 :            :  * GNU General Public License for more details.
      16                 :            :  *
      17                 :            :  * You should have received a copy of the GNU General Public License
      18                 :            :  * along with this program; if not, write to the Free Software
      19                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
      20                 :            :  */
      21                 :            : 
      22                 :            : #ifndef XAPIAN_INCLUDED_QUERY_H
      23                 :            : #define XAPIAN_INCLUDED_QUERY_H
      24                 :            : 
      25                 :            : #if !defined XAPIAN_IN_XAPIAN_H && !defined XAPIAN_LIB_BUILD
      26                 :            : # error "Never use <xapian/query.h> directly; include <xapian.h> instead."
      27                 :            : #endif
      28                 :            : 
      29                 :            : #include <string>
      30                 :            : 
      31                 :            : #include <xapian/attributes.h>
      32                 :            : #include <xapian/intrusive_ptr.h>
      33                 :            : #include <xapian/postingiterator.h>
      34                 :            : #include <xapian/registry.h>
      35                 :            : #include <xapian/termiterator.h>
      36                 :            : #include <xapian/types.h>
      37                 :            : #include <xapian/visibility.h>
      38                 :            : 
      39                 :            : namespace Xapian {
      40                 :            : 
      41                 :            : class PostingSource;
      42                 :            : 
      43                 :            : /// Class representing a query.
      44                 :     215510 : class XAPIAN_VISIBILITY_DEFAULT Query {
      45                 :            :   public:
      46                 :            :     /// Class representing the query internals.
      47                 :            :     class Internal;
      48                 :            :     /// @private @internal Reference counted internals.
      49                 :            :     Xapian::Internal::intrusive_ptr<Internal> internal;
      50                 :            : 
      51                 :            :     /** A query matching no documents.
      52                 :            :      *
      53                 :            :      *  This is a static instance of a default-constructed Xapian::Query
      54                 :            :      *  object.  It is safe to use concurrently from different threads,
      55                 :            :      *  unlike @a MatchAll (this is because MatchNothing has a NULL
      56                 :            :      *  internal object so there's no reference counting happening).
      57                 :            :      */
      58                 :            :     static const Xapian::Query MatchNothing;
      59                 :            : 
      60                 :            :     /** A query matching all documents.
      61                 :            :      *
      62                 :            :      *  This is a static instance of Xapian::Query(std::string()).  If
      63                 :            :      *  you are constructing Query objects in different threads, avoid
      64                 :            :      *  using @a MatchAll as the reference counting of the static object
      65                 :            :      *  can get messed up by concurrent access).
      66                 :            :      */
      67                 :            :     static const Xapian::Query MatchAll;
      68                 :            : 
      69                 :            :     /** Query operators. */
      70                 :            :     enum op {
      71                 :            :         OP_AND = 0,
      72                 :            :         OP_OR = 1,
      73                 :            :         OP_AND_NOT = 2,
      74                 :            :         OP_XOR = 3,
      75                 :            :         OP_AND_MAYBE = 4,
      76                 :            :         OP_FILTER = 5,
      77                 :            :         OP_NEAR = 6,
      78                 :            :         OP_PHRASE = 7,
      79                 :            :         OP_VALUE_RANGE = 8,
      80                 :            :         OP_SCALE_WEIGHT = 9,
      81                 :            : 
      82                 :            :         /** Pick the best N subqueries and combine with OP_OR.
      83                 :            :          *
      84                 :            :          *  If you want to implement a feature which finds documents similar to
      85                 :            :          *  a piece of text, an obvious approach is to build an "OR" query from
      86                 :            :          *  all the terms in the text, and run this query against a database
      87                 :            :          *  containing the documents.  However such a query can contain a lots
      88                 :            :          *  of terms and be quite slow to perform, yet many of these terms
      89                 :            :          *  don't contribute usefully to the results.
      90                 :            :          *
      91                 :            :          *  The OP_ELITE_SET operator can be used instead of OP_OR in this
      92                 :            :          *  situation.  OP_ELITE_SET selects the most important ''N'' terms and
      93                 :            :          *  then acts as an OP_OR query with just these, ignoring any other
      94                 :            :          *  terms.  This will usually return results just as good as the full
      95                 :            :          *  OP_OR query, but much faster.
      96                 :            :          *
      97                 :            :          *  In general, the OP_ELITE_SET operator can be used when you have a
      98                 :            :          *  large OR query, but it doesn't matter if the search completely
      99                 :            :          *  ignores some of the less important terms in the query.
     100                 :            :          *
     101                 :            :          *  The subqueries don't have to be terms, but if they aren't then
     102                 :            :          *  OP_ELITE_SET will look at the estimated frequencies of the
     103                 :            :          *  subqueries and so could pick a subset which don't actually
     104                 :            :          *  match any documents even if the full OR would match some.
     105                 :            :          *
     106                 :            :          *  You can specify a parameter to the query constructor which control
     107                 :            :          *  the number of terms which OP_ELITE_SET will pick.  If not
     108                 :            :          *  specified, this defaults to 10 (Xapian used to default to
     109                 :            :          *  <code>ceil(sqrt(number_of_subqueries))</code> if there are more
     110                 :            :          *  than 100 subqueries, but this rather arbitrary special case was
     111                 :            :          *  dropped in 1.3.0).  For example, this will pick the best 7 terms:
     112                 :            :          *
     113                 :            :          *  <pre>
     114                 :            :          *  Xapian::Query query(Xapian::Query::OP_ELITE_SET, subqs.begin(), subqs.end(), 7);
     115                 :            :          *  </pre>
     116                 :            :          *
     117                 :            :          * If the number of subqueries is less than this threshold,
     118                 :            :          * OP_ELITE_SET behaves identically to OP_OR.
     119                 :            :          */
     120                 :            :         OP_ELITE_SET = 10,
     121                 :            :         OP_VALUE_GE = 11,
     122                 :            :         OP_VALUE_LE = 12,
     123                 :            :         OP_SYNONYM = 13,
     124                 :            :         /** Pick the maximum weight of any subquery.
     125                 :            :          *
     126                 :            :          *  Matches the same documents as @a OP_OR, but the weight contributed
     127                 :            :          *  is the maximum weight from any matching subquery (for OP_OR, it's
     128                 :            :          *  the sum of the weights from the matching subqueries).
     129                 :            :          *
     130                 :            :          *  Added in Xapian 1.3.2.
     131                 :            :          */
     132                 :            :         OP_MAX = 14,
     133                 :            :         /** Wildcard expansion.
     134                 :            :          *
     135                 :            :          *  Added in Xapian 1.3.3.
     136                 :            :          */
     137                 :            :         OP_WILDCARD = 15,
     138                 :            : 
     139                 :            :         /** Edit distance expansion.
     140                 :            :          *
     141                 :            :          *  Expand to terms within a specified edit distance of a target.
     142                 :            :          *
     143                 :            :          *  This works in a fairly similar way to OP_WILDCARD - the difference
     144                 :            :          *  is that instead of expanding to terms matching a wildcard pattern,
     145                 :            :          *  it expands to terms within a specified number of edits (insertion,
     146                 :            :          *  deletion or substitution of a character, or transposition of two
     147                 :            :          *  adjacent characters) of a specified target.
     148                 :            :          *
     149                 :            :          *  @since Added in Xapian 1.5.0.
     150                 :            :          */
     151                 :            :         OP_EDIT_DISTANCE = 16,
     152                 :            : 
     153                 :            :         OP_INVALID = 99,
     154                 :            : 
     155                 :            :         LEAF_TERM = 100,
     156                 :            :         LEAF_POSTING_SOURCE,
     157                 :            :         LEAF_MATCH_ALL,
     158                 :            :         LEAF_MATCH_NOTHING
     159                 :            :     };
     160                 :            : 
     161                 :            :     enum {
     162                 :            :         /** Throw an error if OP_WILDCARD exceeds its expansion limit.
     163                 :            :          *
     164                 :            :          *  Xapian::WildcardError will be thrown when the query is actually
     165                 :            :          *  run.
     166                 :            :          */
     167                 :            :         WILDCARD_LIMIT_ERROR = 0x00,
     168                 :            :         /** Stop expanding when OP_WILDCARD reaches its expansion limit.
     169                 :            :          *
     170                 :            :          *  This makes the wildcard expand to only the first N terms (sorted
     171                 :            :          *  by byte order).
     172                 :            :          */
     173                 :            :         WILDCARD_LIMIT_FIRST = 0x01,
     174                 :            :         /** Limit OP_WILDCARD expansion to the most frequent terms.
     175                 :            :          *
     176                 :            :          *  If OP_WILDCARD would expand to more than its expansion limit, the
     177                 :            :          *  most frequent terms are taken.  This approach works well for cases
     178                 :            :          *  such as expanding a partial term at the end of a query string which
     179                 :            :          *  the user hasn't finished typing yet - as well as being less expense
     180                 :            :          *  to evaluate than the full expansion, using only the most frequent
     181                 :            :          *  terms tends to give better results too.
     182                 :            :          */
     183                 :            :         WILDCARD_LIMIT_MOST_FREQUENT = 0x02,
     184                 :            : 
     185                 :            :         WILDCARD_LIMIT_MASK_ = 0x03,
     186                 :            : 
     187                 :            :         /** Support * which matches 0 or more characters.
     188                 :            :          *
     189                 :            :          *  @since Added in Xapian 1.5.0.
     190                 :            :          */
     191                 :            :         WILDCARD_PATTERN_MULTI = 0x10,
     192                 :            : 
     193                 :            :         /** Support ? which matches a single character.
     194                 :            :          *
     195                 :            :          *  @since Added in Xapian 1.5.0.
     196                 :            :          */
     197                 :            :         WILDCARD_PATTERN_SINGLE = 0x20,
     198                 :            : 
     199                 :            :         /** Enable all supported glob-like features.
     200                 :            :          *
     201                 :            :          *  @since Added in Xapian 1.5.0.
     202                 :            :          */
     203                 :            :         WILDCARD_PATTERN_GLOB = WILDCARD_PATTERN_MULTI|WILDCARD_PATTERN_SINGLE
     204                 :            :     };
     205                 :            : 
     206                 :            :     /// Default constructor.
     207                 :     791694 :     XAPIAN_NOTHROW(Query()) { }
     208                 :            : 
     209                 :            :     /// Destructor.
     210                 :    4844624 :     ~Query() { }
     211                 :            : 
     212                 :            :     /** Copying is allowed.
     213                 :            :      *
     214                 :            :      *  The internals are reference counted, so copying is cheap.
     215                 :            :      */
     216                 :    1066300 :     Query(const Query & o) : internal(o.internal) { }
     217                 :            : 
     218                 :            :     /** Copying is allowed.
     219                 :            :      *
     220                 :            :      *  The internals are reference counted, so assignment is cheap.
     221                 :            :      */
     222                 :     536444 :     Query & operator=(const Query & o) { internal = o.internal; return *this; }
     223                 :            : 
     224                 :            :     /// Move constructor.
     225                 :     552384 :     Query(Query &&) = default;
     226                 :            : 
     227                 :            :     /// Move assignment operator.
     228                 :            :     Query & operator=(Query &&) = default;
     229                 :            : 
     230                 :            :     /** Construct a Query object for a term. */
     231                 :            :     Query(const std::string & term,
     232                 :            :           Xapian::termcount wqf = 1,
     233                 :            :           Xapian::termpos pos = 0);
     234                 :            : 
     235                 :            :     /** Construct a Query object for a PostingSource. */
     236                 :            :     explicit Query(Xapian::PostingSource * source);
     237                 :            : 
     238                 :            :     /** Scale using OP_SCALE_WEIGHT.
     239                 :            :      *
     240                 :            :      *  @param factor Non-negative real number to multiply weights by.
     241                 :            :      *  @param subquery Query object to scale weights from.
     242                 :            :      */
     243                 :            :     Query(double factor, const Xapian::Query & subquery);
     244                 :            : 
     245                 :            :     /** Scale using OP_SCALE_WEIGHT.
     246                 :            :      *
     247                 :            :      *  In this form, the op_ parameter is totally redundant - use
     248                 :            :      *  Query(factor, subquery) in preference.
     249                 :            :      *
     250                 :            :      *  @param op_      Must be OP_SCALE_WEIGHT.
     251                 :            :      *  @param factor   Non-negative real number to multiply weights by.
     252                 :            :      *  @param subquery Query object to scale weights from.
     253                 :            :      */
     254                 :            :     Query(op op_, const Xapian::Query & subquery, double factor);
     255                 :            : 
     256                 :            :     /** Construct a Query object by combining two others.
     257                 :            :      *
     258                 :            :      *  @param op_      The operator to combine the queries with.
     259                 :            :      *  @param a        First subquery.
     260                 :            :      *  @param b        Second subquery.
     261                 :            :      */
     262                 :      57708 :     Query(op op_, const Xapian::Query & a, const Xapian::Query & b)
     263                 :      57738 :     {
     264         [ +  - ]:      57708 :         init(op_, 2);
     265 [ +  + ][ +  + ]:      57708 :         bool positional = (op_ == OP_NEAR || op_ == OP_PHRASE);
     266         [ +  + ]:      57708 :         add_subquery(positional, a);
     267         [ +  - ]:      57678 :         add_subquery(positional, b);
     268         [ +  - ]:      57678 :         done();
     269                 :      57678 :     }
     270                 :            : 
     271                 :            :     /** Construct a Query object by combining two terms.
     272                 :            :      *
     273                 :            :      *  @param op_      The operator to combine the terms with.
     274                 :            :      *  @param a        First term.
     275                 :            :      *  @param b        Second term.
     276                 :            :      */
     277                 :         11 :     Query(op op_, const std::string & a, const std::string & b)
     278                 :         11 :     {
     279         [ +  - ]:         11 :         init(op_, 2);
     280         [ +  - ]:         11 :         add_subquery(false, a);
     281         [ +  - ]:         11 :         add_subquery(false, b);
     282         [ +  - ]:         11 :         done();
     283                 :         11 :     }
     284                 :            : 
     285                 :            :     /** Construct a Query object for a single-ended value range.
     286                 :            :      *
     287                 :            :      *  @param op_              Must be OP_VALUE_LE or OP_VALUE_GE currently.
     288                 :            :      *  @param slot             The value slot to work over.
     289                 :            :      *  @param range_limit      The limit of the range.
     290                 :            :      */
     291                 :            :     Query(op op_, Xapian::valueno slot, const std::string & range_limit);
     292                 :            : 
     293                 :            :     /** Construct a Query object for a value range.
     294                 :            :      *
     295                 :            :      *  @param op_              Must be OP_VALUE_RANGE currently.
     296                 :            :      *  @param slot             The value slot to work over.
     297                 :            :      *  @param range_lower      Lower end of the range.
     298                 :            :      *  @param range_upper      Upper end of the range.
     299                 :            :      */
     300                 :            :     Query(op op_, Xapian::valueno slot,
     301                 :            :           const std::string & range_lower, const std::string & range_upper);
     302                 :            : 
     303                 :            :     /** Query constructor for OP_EDIT_DISTANCE and OP_WILDCARD queries.
     304                 :            :      *
     305                 :            :      *  @param op_      Must be OP_EDIT_DISTANCE or OP_WILDCARD
     306                 :            :      *  @param pattern  The wildcard pattern (for OP_WILDCARD) or target string
     307                 :            :      *                  (for OP_EDIT_DISTANCE).  See @a flags which affects
     308                 :            :      *                  how this pattern is interpreted.
     309                 :            :      *  @param max_expansion    The maximum number of terms to expand to
     310                 :            :      *                          (default: 0, which means no limit)
     311                 :            :      *  @param flags    Flags controlling aspects of the wildcarding - this
     312                 :            :      *                  consists of a bitwise OR of:
     313                 :            :      *
     314                 :            :      *                  * At most one of @a WILDCARD_LIMIT_ERROR (the default),
     315                 :            :      *                    @a WILDCARD_LIMIT_FIRST or
     316                 :            :      *                    @a WILDCARD_LIMIT_MOST_FREQUENT specifying how to
     317                 :            :      *                    enforce max_expansion.
     318                 :            :      *
     319                 :            :      *                    When searching multiple databases, the expansion
     320                 :            :      *                    limit is currently applied independently for each
     321                 :            :      *                    database, so the total number of terms may be higher
     322                 :            :      *                    than the limit.  This is arguably a bug, and may
     323                 :            :      *                    change in future versions.
     324                 :            :      *
     325                 :            :      *                  * For OP_WILDCARD: Zero or more of
     326                 :            :      *                    @a WILDCARD_PATTERN_MULTI and
     327                 :            :      *                    @a WILDCARD_PATTERN_SINGLE, which specify whether
     328                 :            :      *                    '*' (matching zero or more characters) and '?'
     329                 :            :      *                    (matching exactly one character) are supported.
     330                 :            :      *                    If neither is specified, then a Xapian-1.4-compatible
     331                 :            :      *                    mode is used where the pattern matches terms which
     332                 :            :      *                    start with the pattern interpreted as a literal
     333                 :            :      *                    string.
     334                 :            :      *
     335                 :            :      *  @param combiner The @a Query::op to combine the terms with - one of
     336                 :            :      *                  @a OP_SYNONYM (the default), @a OP_OR or @a OP_MAX.
     337                 :            :      *
     338                 :            :      *  For OP_WILDCARD: A leading wildcard won't match terms starting with an
     339                 :            :      *  ASCII capital letter, as this is assumed to be part of a term prefix.
     340                 :            :      */
     341                 :            :     Query(op op_,
     342                 :            :           const std::string & pattern,
     343                 :            :           Xapian::termcount max_expansion = 0,
     344                 :            :           int flags = WILDCARD_LIMIT_ERROR,
     345                 :            :           op combiner = OP_SYNONYM);
     346                 :            : 
     347                 :            :     /** Query constructor for OP_EDIT_DISTANCE queries.
     348                 :            :      *
     349                 :            :      *  This form supports some additional parameters.
     350                 :            :      *
     351                 :            :      *  @param op_      Must be OP_EDIT_DISTANCE.
     352                 :            :      *  @param pattern  The target string.
     353                 :            :      *  @param max_expansion    The maximum number of terms to expand to
     354                 :            :      *                          (default: 0, which means no limit)
     355                 :            :      *  @param flags    Flags controlling aspects of the wildcarding:
     356                 :            :      *
     357                 :            :      *                  * At most one of @a WILDCARD_LIMIT_ERROR (the default),
     358                 :            :      *                    @a WILDCARD_LIMIT_FIRST or
     359                 :            :      *                    @a WILDCARD_LIMIT_MOST_FREQUENT specifying how to
     360                 :            :      *                    enforce max_expansion.
     361                 :            :      *
     362                 :            :      *                    When searching multiple databases, the expansion
     363                 :            :      *                    limit is currently applied independently for each
     364                 :            :      *                    database, so the total number of terms may be higher
     365                 :            :      *                    than the limit.  This is arguably a bug, and may
     366                 :            :      *                    change in future versions.
     367                 :            :      *
     368                 :            :      *  @param combiner The @a Query::op to combine the terms with - one of
     369                 :            :      *                  @a OP_SYNONYM (the default), @a OP_OR or @a OP_MAX.
     370                 :            :      *  @param edit_distance
     371                 :            :      *                  The maximum number of edits allowed between a term
     372                 :            :      *                  and @a target (an edit is insertion, deletion or
     373                 :            :      *                  substitution of a character, or transposition of two
     374                 :            :      *                  adjacent characters).  Default: 2
     375                 :            :      *  @param min_prefix_len
     376                 :            :      *                  The length in bytes of any initial substring of target
     377                 :            :      *                  that is required to match exactly.  Default: 0
     378                 :            :      */
     379                 :            :     Query(op op_,
     380                 :            :           const std::string& pattern,
     381                 :            :           Xapian::termcount max_expansion,
     382                 :            :           int flags,
     383                 :            :           op combiner,
     384                 :            :           unsigned edit_distance,
     385                 :            :           size_t min_prefix_len = 0);
     386                 :            : 
     387                 :            :     /** Construct a Query object from a begin/end iterator pair.
     388                 :            :      *
     389                 :            :      *  Dereferencing the iterator should return a Xapian::Query, a non-NULL
     390                 :            :      *  Xapian::Query*, a std::string or a type which converts to one of
     391                 :            :      *  these (e.g. const char*).
     392                 :            :      *
     393                 :            :      *  @param op_      The operator to combine the queries with.
     394                 :            :      *  @param begin    Begin iterator.
     395                 :            :      *  @param end      End iterator.
     396                 :            :      *  @param window   Window size for OP_NEAR and OP_PHRASE, or 0 to use the
     397                 :            :      *                  number of subqueries as the window size (default: 0).
     398                 :            :      */
     399                 :            :     template<typename I>
     400                 :      64293 :     Query(op op_, I begin, I end, Xapian::termcount window = 0)
     401                 :      64307 :     {
     402   [ +  +  +  +  :      64293 :         if (begin != end) {
             +  -  #  +  
                      + ]
     403                 :            :             typedef typename std::iterator_traits<I>::iterator_category iterator_category;
     404 [ +  - ][ +  - ]:      64273 :             init(op_, window, begin, end, iterator_category());
         [ #  # ][ #  # ]
         [ #  # ][ +  - ]
     405 [ +  + ][ +  + ]:      64259 :             bool positional = (op_ == OP_NEAR || op_ == OP_PHRASE);
         [ +  - ][ -  + ]
         [ +  - ][ -  + ]
     406 [ +  + ][ +  + ]:     246294 :             for (I i = begin; i != end; ++i) {
         [ +  + ][ #  # ]
         [ +  + ][ +  + ]
         [ #  # ][ #  # ]
         [ #  # ][ +  - ]
         [ +  - ][ +  + ]
     407         [ +  + ]:     182049 :                 add_subquery(positional, *i);
              [ +  +  - ]
            [ #  # ][ + ]
         [ +  - ][ #  # ]
         [ #  # ][ +  - ]
     408                 :            :             }
     409 [ +  - ][ +  - ]:      64245 :             done();
         [ #  # ][ +  - ]
     410                 :            :         }
     411                 :      64279 :     }
     412                 :            : 
     413                 :            : #ifdef SWIG
     414                 :            :     // SWIG's %template doesn't seem to handle a templated ctor so we
     415                 :            :     // provide this fake specialised form of the above prototype.
     416                 :            :     Query(op op_, XapianSWIGQueryItor qbegin, XapianSWIGQueryItor qend,
     417                 :            :           Xapian::termcount parameter = 0);
     418                 :            : 
     419                 :            : # ifdef SWIGJAVA
     420                 :            :     Query(op op_, XapianSWIGStrItor qbegin, XapianSWIGStrItor qend,
     421                 :            :           Xapian::termcount parameter = 0);
     422                 :            : # endif
     423                 :            : #endif
     424                 :            : 
     425                 :            :     /** Begin iterator for terms in the query object.
     426                 :            :      *
     427                 :            :      *  The iterator returns terms in ascending query position order, and
     428                 :            :      *  will return the same term in each unique position it occurs in.
     429                 :            :      *  If you want the terms in sorted order and without duplicates, see
     430                 :            :      *  get_unique_terms_begin().
     431                 :            :      */
     432                 :            :     const TermIterator get_terms_begin() const;
     433                 :            : 
     434                 :            :     /// End iterator for terms in the query object.
     435                 :        543 :     const TermIterator XAPIAN_NOTHROW(get_terms_end() const) {
     436                 :        543 :         return TermIterator();
     437                 :            :     }
     438                 :            : 
     439                 :            :     /** Begin iterator for unique terms in the query object.
     440                 :            :      *
     441                 :            :      *  Terms are sorted and terms with the same name removed from the list.
     442                 :            :      *
     443                 :            :      *  If you want the terms in ascending query position order, see
     444                 :            :      *  get_terms_begin().
     445                 :            :      */
     446                 :            :     const TermIterator get_unique_terms_begin() const;
     447                 :            : 
     448                 :            :     /** Return the length of this query object. */
     449                 :            :     Xapian::termcount XAPIAN_NOTHROW(get_length() const) XAPIAN_PURE_FUNCTION;
     450                 :            : 
     451                 :            :     /** Check if this query is Xapian::Query::MatchNothing. */
     452                 :     339269 :     bool XAPIAN_NOTHROW(empty() const) {
     453                 :     339269 :         return internal.get() == 0;
     454                 :            :     }
     455                 :            : 
     456                 :            :     /** Serialise this object into a string. */
     457                 :            :     std::string serialise() const;
     458                 :            : 
     459                 :            :     /** Unserialise a string and return a Query object.
     460                 :            :      *
     461                 :            :      *  @param serialised       the string to unserialise.
     462                 :            :      *  @param reg              Xapian::Registry object to use to unserialise
     463                 :            :      *                          user-subclasses of Xapian::PostingSource
     464                 :            :      *                          (default: standard registry).
     465                 :            :      */
     466                 :            :     static const Query unserialise(const std::string & serialised,
     467                 :            :                                    const Registry & reg = Registry());
     468                 :            : 
     469                 :            :     /** Get the type of the top level of the query. */
     470                 :            :     op XAPIAN_NOTHROW(get_type() const) XAPIAN_PURE_FUNCTION;
     471                 :            : 
     472                 :            :     /** Get the number of subqueries of the top level query. */
     473                 :            :     size_t XAPIAN_NOTHROW(get_num_subqueries() const) XAPIAN_PURE_FUNCTION;
     474                 :            : 
     475                 :            :     /** Get the wqf parameter of a leaf node. */
     476                 :            :     Xapian::termcount get_leaf_wqf() const;
     477                 :            : 
     478                 :            :     /** Get the pos parameter of a leaf node. */
     479                 :            :     Xapian::termpos get_leaf_pos() const;
     480                 :            : 
     481                 :            :     /** Read a top level subquery.
     482                 :            :       *
     483                 :            :       * @param n  Return the n-th subquery (starting from 0) - only valid when
     484                 :            :       *           0 <= n < get_num_subqueries().
     485                 :            :       */
     486                 :            :     const Query get_subquery(size_t n) const;
     487                 :            : 
     488                 :            :     /// Return a string describing this object.
     489                 :            :     std::string get_description() const;
     490                 :            : 
     491                 :            :     /** Combine with another Xapian::Query object using OP_AND.
     492                 :            :      *
     493                 :            :      *  @since Since Xapian 1.4.10, when called on a Query object which is
     494                 :            :      *  OP_AND and has a reference count of 1, then @a o is appended as a new
     495                 :            :      *  subquery (provided @a o is a different Query object and
     496                 :            :      *  <code>!o.empty()</code>).
     497                 :            :      */
     498                 :            :     const Query operator&=(const Query & o);
     499                 :            : 
     500                 :            :     /** Combine with another Xapian::Query object using OP_OR.
     501                 :            :      *
     502                 :            :      *  @since Since Xapian 1.4.10, when called on a Query object which is
     503                 :            :      *  OP_OR and has a reference count of 1, then @a o is appended as a new
     504                 :            :      *  subquery (provided @a o is a different Query object and
     505                 :            :      *  <code>!o.empty()</code>).
     506                 :            :      */
     507                 :            :     const Query operator|=(const Query & o);
     508                 :            : 
     509                 :            :     /** Combine with another Xapian::Query object using OP_XOR.
     510                 :            :      *
     511                 :            :      *  @since Since Xapian 1.4.10, when called on a Query object which is
     512                 :            :      *  OP_XOR and has a reference count of 1, then @a o is appended as a new
     513                 :            :      *  subquery (provided @a o is a different Query object and
     514                 :            :      *  <code>!o.empty()</code>).
     515                 :            :      */
     516                 :            :     const Query operator^=(const Query & o);
     517                 :            : 
     518                 :            :     /** Scale using OP_SCALE_WEIGHT.
     519                 :            :      *
     520                 :            :      *  @param factor Non-negative real number to multiply weights by.
     521                 :            :      */
     522                 :            :     const Query operator*=(double factor) {
     523                 :            :         return (*this = Query(factor, *this));
     524                 :            :     }
     525                 :            : 
     526                 :            :     /** Inverse scale using OP_SCALE_WEIGHT.
     527                 :            :      *
     528                 :            :      *  @param factor Positive real number to divide weights by.
     529                 :            :      */
     530                 :            :     const Query operator/=(double factor) {
     531                 :            :         return (*this = Query(1.0 / factor, *this));
     532                 :            :     }
     533                 :            : 
     534                 :            :     /// @private @internal Wrap an existing Internal.
     535                 :    1738704 :     explicit Query(Internal * internal_) : internal(internal_) { }
     536                 :            : 
     537                 :            :     /** Construct with just an operator.
     538                 :            :      *
     539                 :            :      *  @param op_ The operator to use - currently only OP_INVALID is useful.
     540                 :            :      */
     541                 :        192 :     explicit Query(Query::op op_) {
     542         [ +  - ]:         96 :         init(op_, 0);
     543 [ -  + ][ #  # ]:         96 :         if (op_ != Query::OP_INVALID) done();
     544                 :         96 :     }
     545                 :            : 
     546                 :            :   private:
     547                 :            :     void init(Query::op op_, size_t n_subqueries, Xapian::termcount window = 0);
     548                 :            : 
     549                 :            :     template<typename I>
     550                 :      13605 :     void init(Query::op op_, Xapian::termcount window,
     551                 :            :               const I & begin, const I & end, std::random_access_iterator_tag)
     552                 :            :     {
     553                 :      13605 :         init(op_, end - begin, window);
     554                 :      13605 :     }
     555                 :            : 
     556                 :            :     template<typename I>
     557                 :      50654 :     void init(Query::op op_, Xapian::termcount window,
     558                 :            :               const I &, const I &, std::input_iterator_tag)
     559                 :            :     {
     560                 :      50654 :         init(op_, 0, window);
     561                 :      50654 :     }
     562                 :            : 
     563                 :            :     void add_subquery(bool positional, const Xapian::Query & subquery);
     564                 :            : 
     565                 :       5019 :     void add_subquery(bool, const std::string & subquery) {
     566         [ +  - ]:       5019 :         add_subquery(false, Xapian::Query(subquery));
     567                 :       5019 :     }
     568                 :            : 
     569                 :          2 :     void add_subquery(bool positional, const Xapian::Query * subquery) {
     570                 :            :         // FIXME: subquery NULL?
     571                 :          2 :         add_subquery(positional, *subquery);
     572                 :          2 :     }
     573                 :            : 
     574                 :            :     void done();
     575                 :            : };
     576                 :            : 
     577                 :            : /** Combine two Xapian::Query objects using OP_AND. */
     578                 :            : inline const Query
     579                 :         19 : operator&(const Query & a, const Query & b)
     580                 :            : {
     581                 :         19 :     return Query(Query::OP_AND, a, b);
     582                 :            : }
     583                 :            : 
     584                 :            : /** Combine two Xapian::Query objects using OP_OR. */
     585                 :            : inline const Query
     586                 :        601 : operator|(const Query & a, const Query & b)
     587                 :            : {
     588                 :        601 :     return Query(Query::OP_OR, a, b);
     589                 :            : }
     590                 :            : 
     591                 :            : /** Combine two Xapian::Query objects using OP_XOR. */
     592                 :            : inline const Query
     593                 :          8 : operator^(const Query & a, const Query & b)
     594                 :            : {
     595                 :          8 :     return Query(Query::OP_XOR, a, b);
     596                 :            : }
     597                 :            : 
     598                 :            : /** Scale a Xapian::Query object using OP_SCALE_WEIGHT.
     599                 :            :  *
     600                 :            :  *  @param factor Non-negative real number to multiply weights by.
     601                 :            :  *  @param q Xapian::Query object.
     602                 :            :  */
     603                 :            : inline const Query
     604                 :          2 : operator*(double factor, const Query & q)
     605                 :            : {
     606                 :          2 :     return Query(factor, q);
     607                 :            : }
     608                 :            : 
     609                 :            : /** Scale a Xapian::Query object using OP_SCALE_WEIGHT.
     610                 :            :  *
     611                 :            :  *  @param q Xapian::Query object.
     612                 :            :  *  @param factor Non-negative real number to multiply weights by.
     613                 :            :  */
     614                 :            : inline const Query
     615                 :          1 : operator*(const Query & q, double factor)
     616                 :            : {
     617                 :          1 :     return Query(factor, q);
     618                 :            : }
     619                 :            : 
     620                 :            : /** Inverse-scale a Xapian::Query object using OP_SCALE_WEIGHT.
     621                 :            :  *
     622                 :            :  *  @param factor Positive real number to divide weights by.
     623                 :            :  *  @param q Xapian::Query object.
     624                 :            :  */
     625                 :            : inline const Query
     626                 :          2 : operator/(const Query & q, double factor)
     627                 :            : {
     628                 :          2 :     return Query(1.0 / factor, q);
     629                 :            : }
     630                 :            : 
     631                 :            : /** @private @internal */
     632                 :            : class InvertedQuery_ {
     633                 :            :     const Query & query;
     634                 :            : 
     635                 :            :     void operator=(const InvertedQuery_ &);
     636                 :            : 
     637                 :         56 :     explicit InvertedQuery_(const Query & query_) : query(query_) { }
     638                 :            : 
     639                 :            :   public:
     640                 :            :     // GCC 4.2 seems to needs a copy ctor.
     641                 :            :     InvertedQuery_(const InvertedQuery_ & o) : query(o.query) { }
     642                 :            : 
     643                 :          2 :     operator Query() const {
     644 [ +  - ][ +  - ]:          2 :         return Query(Query::OP_AND_NOT, Query(std::string()), query);
     645                 :            :     }
     646                 :            : 
     647                 :            :     friend const InvertedQuery_ operator~(const Query &q);
     648                 :            : 
     649                 :            :     friend const Query operator&(const Query & a, const InvertedQuery_ & b);
     650                 :            : 
     651                 :            :     friend const Query operator&=(Query & a, const InvertedQuery_ & b);
     652                 :            : };
     653                 :            : 
     654                 :            : /** Combine two Xapian::Query objects using OP_AND_NOT.
     655                 :            :  *
     656                 :            :  *  E.g. Xapian::Query q = q1 &~ q2;
     657                 :            :  */
     658                 :            : inline const Query
     659                 :         30 : operator&(const Query & a, const InvertedQuery_ & b)
     660                 :            : {
     661                 :         30 :     return Query(Query::OP_AND_NOT, a, b.query);
     662                 :            : }
     663                 :            : 
     664                 :            : /** Combine two Xapian::Query objects using OP_AND_NOT with result in the first.
     665                 :            :  *
     666                 :            :  *  E.g. q1 &=~ q2;
     667                 :            :  */
     668                 :            : inline const Query
     669                 :         24 : operator&=(Query & a, const InvertedQuery_ & b)
     670                 :            : {
     671 [ +  - ][ +  - ]:         24 :     return (a = Query(Query::OP_AND_NOT, a, b.query));
     672                 :            : }
     673                 :            : 
     674                 :            : #ifndef DOXYGEN /* @internal doesn't seem to avoid a warning here. */
     675                 :            : /** @internal Helper to allow q1 &~ q2 to work. */
     676                 :            : inline const InvertedQuery_
     677                 :         56 : operator~(const Query &q)
     678                 :            : {
     679                 :         56 :     return InvertedQuery_(q);
     680                 :            : }
     681                 :            : #endif
     682                 :            : 
     683                 :            : namespace Internal {
     684                 :            : class AndContext;
     685                 :            : class BoolOrContext;
     686                 :            : class OrContext;
     687                 :            : class XorContext;
     688                 :            : 
     689                 :            : class PostList;
     690                 :            : class QueryOptimiser;
     691                 :            : }
     692                 :            : 
     693                 :            : /** @private @internal */
     694                 :            : class Query::Internal : public Xapian::Internal::intrusive_base {
     695                 :            :   public:
     696                 :     667764 :     XAPIAN_NOTHROW(Internal()) { }
     697                 :            : 
     698                 :            :     virtual ~Internal();
     699                 :            : 
     700                 :            :     virtual
     701                 :            :     Xapian::Internal::PostList* postlist(Xapian::Internal::QueryOptimiser* qopt,
     702                 :            :                                          double factor) const = 0;
     703                 :            : 
     704                 :            :     virtual bool postlist_sub_and_like(Xapian::Internal::AndContext& ctx,
     705                 :            :                                        Xapian::Internal::QueryOptimiser* qopt,
     706                 :            :                                        double factor) const;
     707                 :            : 
     708                 :            :     virtual void postlist_sub_bool_or_like(Xapian::Internal::BoolOrContext& ctx,
     709                 :            :                                            Xapian::Internal::QueryOptimiser* qopt) const;
     710                 :            : 
     711                 :            :     virtual void postlist_sub_or_like(Xapian::Internal::OrContext& ctx,
     712                 :            :                                       Xapian::Internal::QueryOptimiser* qopt,
     713                 :            :                                       double factor) const;
     714                 :            : 
     715                 :            :     virtual void postlist_sub_xor(Xapian::Internal::XorContext& ctx,
     716                 :            :                                   Xapian::Internal::QueryOptimiser* qopt,
     717                 :            :                                   double factor) const;
     718                 :            : 
     719                 :            :     virtual termcount XAPIAN_NOTHROW(get_length() const) XAPIAN_PURE_FUNCTION;
     720                 :            : 
     721                 :            :     virtual void serialise(std::string & result) const = 0;
     722                 :            : 
     723                 :            :     static Query::Internal * unserialise(const char ** p, const char * end, const Registry & reg);
     724                 :            : 
     725                 :            :     virtual Query::op XAPIAN_NOTHROW(get_type() const) XAPIAN_PURE_FUNCTION = 0;
     726                 :            :     virtual size_t XAPIAN_NOTHROW(get_num_subqueries() const) XAPIAN_PURE_FUNCTION;
     727                 :            :     virtual const Query get_subquery(size_t n) const;
     728                 :            :     virtual termcount get_wqf() const;
     729                 :            :     virtual termpos get_pos() const;
     730                 :            : 
     731                 :            :     virtual std::string get_description() const = 0;
     732                 :            : 
     733                 :            :     // Pass argument as void* to avoid need to include <vector>.
     734                 :            :     virtual void gather_terms(void * void_terms) const;
     735                 :            : };
     736                 :            : 
     737                 :            : inline const Query
     738                 :        137 : Query::operator&=(const Query & o)
     739                 :            : {
     740         [ +  + ]:        137 :     if (o.empty()) {
     741                 :            :         // q &= empty_query sets q to empty_query.
     742                 :          1 :         *this = o;
     743 [ +  - ][ +  + ]:        271 :     } else if (this != &o &&
     744         [ +  + ]:        270 :                internal.get() &&
     745 [ +  + ][ +  + ]:        406 :                internal->_refs == 1 &&
     746                 :        122 :                get_type() == OP_AND) {
     747                 :            :         // Appending a subquery to an existing AND.
     748                 :         19 :         add_subquery(false, o);
     749                 :            :     } else {
     750         [ +  - ]:        117 :         *this = Query(OP_AND, *this, o);
     751                 :            :     }
     752                 :        137 :     return *this;
     753                 :            : }
     754                 :            : 
     755                 :            : inline const Query
     756                 :        992 : Query::operator|=(const Query & o)
     757                 :            : {
     758         [ +  + ]:        992 :     if (o.empty()) {
     759                 :            :         // q |= empty_query is a no-op.
     760 [ +  + ][ +  + ]:       1981 :     } else if (this != &o &&
     761         [ +  + ]:       1966 :                internal.get() &&
     762 [ +  + ][ +  + ]:       2957 :                internal->_refs == 1 &&
     763                 :        975 :                get_type() == OP_OR) {
     764                 :            :         // Appending a subquery to an existing OR.
     765                 :        526 :         add_subquery(false, o);
     766                 :            :     } else {
     767         [ +  - ]:        465 :         *this = Query(OP_OR, *this, o);
     768                 :            :     }
     769                 :        992 :     return *this;
     770                 :            : }
     771                 :            : 
     772                 :            : inline const Query
     773                 :         15 : Query::operator^=(const Query & o)
     774                 :            : {
     775         [ +  + ]:         15 :     if (o.empty()) {
     776                 :            :         // q ^= empty_query is a no-op.
     777         [ +  + ]:         14 :     } else if (internal.get() == o.internal.get()) {
     778                 :            :         // q ^= q gives MatchNothing.
     779                 :          2 :         internal = NULL;
     780 [ +  + ][ +  + ]:         36 :     } else if (internal.get() &&
     781 [ +  - ][ +  + ]:         24 :                internal->_refs == 1 &&
     782                 :         11 :                get_type() == OP_XOR) {
     783                 :            :         // Appending a subquery to an existing XOR.
     784                 :          1 :         add_subquery(false, o);
     785                 :            :     } else {
     786         [ +  - ]:         11 :         *this = Query(OP_XOR, *this, o);
     787                 :            :     }
     788                 :         15 :     return *this;
     789                 :            : }
     790                 :            : 
     791                 :            : }
     792                 :            : 
     793                 :            : #endif // XAPIAN_INCLUDED_QUERY_H

Generated by: LCOV version 1.11