Ticket #280: patch

File patch, 21.5 KB (added by Richard Boulton, 16 years ago)

Patch moving Query::Internal out of query.h, by using an InternalPtr class.

  • tests/internaltest.cc

     
    451451    for (query = queries.begin(); query != queries.end(); query++) {
    452452        Xapian::Query::Internal * qint;
    453453
    454         s = query->internal->serialise();
     454        s = query->internalptr->get()->serialise();
    455455        qint = Xapian::Query::Internal::unserialise(s);
    456456
    457457        TEST(qint->serialise() == s);
  • include/xapian/query.h

     
    3333#include <xapian/termiterator.h>
    3434#include <xapian/visibility.h>
    3535
    36 // FIXME: sort this out so we avoid exposing Xapian::Query::Internal
    37 // - we need to at present so that the Xapian::Query's template ctors
    38 // compile.
    39 class LocalSubMatch;
    40 class MultiMatch;
    41 class QueryOptimiser;
    42 struct SortPosName;
    43 
    4436namespace Xapian {
    4537
    4638class PostingSource;
     
    5345    public:
    5446        /// Class holding details of the query
    5547        class Internal;
    56         /// @private @internal Reference counted internals.
    57         Xapian::Internal::RefCntPtr<Internal> internal;
    5848
     49        /// Refcount pointer to class holding details of the query.
     50        struct InternalPtr;
     51
     52        /// @private @internal Pointer to reference counted internals.
     53        InternalPtr * internalptr;
     54
    5955        /// Enum of possible query operations
    6056        typedef enum {
    6157            /// Return iff both subqueries are satisfied
     
    252248
    253249template <class Iterator>
    254250Query::Query(Query::op op_, Iterator qbegin, Iterator qend, termcount parameter)
    255     : internal(0)
     251    : internalptr(0)
    256252{
    257253    try {
    258254        start_construction(op_, parameter);
     
    270266    }
    271267}
    272268
    273 #ifndef SWIG // SWIG has no interest in the internal class, so hide it completely.
    274 
    275 /// @internal Internal class, implementing most of Xapian::Query.
    276 class XAPIAN_VISIBILITY_DEFAULT Query::Internal : public Xapian::Internal::RefCntBase {
    277     friend class ::LocalSubMatch;
    278     friend class ::MultiMatch;
    279     friend class ::QueryOptimiser;
    280     friend struct ::SortPosName;
    281     friend class Query;
    282     public:
    283         static const int OP_LEAF = -1;
    284         static const int OP_EXTERNAL_SOURCE = -2;
    285 
    286         /// The container type for storing pointers to subqueries
    287         typedef std::vector<Internal *> subquery_list;
    288 
    289         /// Type storing the operation
    290         typedef int op_t;
    291 
    292     private:
    293         /// Operation to be performed at this node
    294         Xapian::Query::Internal::op_t op;
    295 
    296         /// Sub queries on which to perform operation
    297         subquery_list subqs;
    298 
    299         /** For NEAR or PHRASE, how close terms must be to match: all terms
    300          *  within the operation must occur in a window of this size.
    301          *
    302          * For ELITE_SET, the number of terms to select from those specified.
    303          *
    304          * For RANGE, the value number to apply the range test to.
    305          */
    306         Xapian::termcount parameter;
    307 
    308         /** Term that this node represents, or start of a range query.
    309          *
    310          *  For a leaf node, this holds the term name.  For an OP_VALUE_RANGE
    311          *  query this holds the start of the range.  For an OP_VALUE_GE or
    312          *  OP_VALUE_LE query this holds the value to compare against.
    313          */
    314         std::string tname;
    315 
    316         /** Used to store the end of a range query. */
    317         std::string str_parameter;
    318 
    319         /// Position in query of this term - leaf node only
    320         Xapian::termpos term_pos;
    321 
    322         /// Within query frequency of this term - leaf node only
    323         Xapian::termcount wqf;
    324 
    325         /// External posting source.
    326         Xapian::PostingSource * external_source;
    327 
    328         /** swap the contents of this with another Xapian::Query::Internal,
    329          *  in a way which is guaranteed not to throw.  This is
    330          *  used with the assignment operator to make it exception
    331          *  safe.
    332          *  It's important to adjust swap with any addition of
    333          *  member variables!
    334          */
    335         void swap(Query::Internal &other);
    336 
    337         /// Copy another Xapian::Query::Internal into self.
    338         void initialise_from_copy(const Query::Internal & copyme);
    339 
    340         void accumulate_terms(
    341             std::vector<std::pair<std::string, Xapian::termpos> > &terms) const;
    342 
    343         /** Simplify the query.
    344          *  For example, an AND query with only one subquery would become the
    345          *  subquery itself.
    346          */
    347         Internal * simplify_query();
    348 
    349         /** Perform checks that query is valid. (eg, has correct number of
    350          *  sub queries.)  Throw an exception if not.  This is initially called
    351          *  on the query before any simplifications have been made, and after
    352          *  simplications.
    353          */
    354         void validate_query() const;
    355 
    356         /** Simplify any matchnothing subqueries, either eliminating them,
    357          *  or setting this query to matchnothing, depending on the query
    358          *  operator.  Returns true if simplification resulted in a
    359          *  matchnothing query.
    360          */
    361         bool simplify_matchnothing();
    362 
    363         /** Get a string describing the given query type.
    364          */
    365         static std::string get_op_name(Xapian::Query::Internal::op_t op);
    366 
    367         /** Collapse the subqueries together if appropriate.
    368          */
    369         void collapse_subqs();
    370 
    371         /** Flatten a query structure, by changing, for example,
    372          *  "A NEAR (B AND C)" to "(A NEAR B) AND (A NEAR C)"
    373          */
    374         void flatten_subqs();
    375 
    376         /** Implementation of serialisation; called recursively.
    377          */
    378         std::string serialise(Xapian::termpos & curpos) const;
    379 
    380     public:
    381         /** Copy constructor. */
    382         Internal(const Query::Internal & copyme);
    383 
    384         /** Assignment. */
    385         void operator=(const Query::Internal & copyme);
    386 
    387         /** A query consisting of a single term. */
    388         explicit Internal(const std::string & tname_, Xapian::termcount wqf_ = 1,
    389                           Xapian::termpos term_pos_ = 0);
    390 
    391         /** Create internals given only the operator and a parameter. */
    392         Internal(op_t op_, Xapian::termcount parameter);
    393 
    394         /** Construct a range query on a document value. */
    395         Internal(op_t op_, Xapian::valueno valno,
    396                  const std::string &begin, const std::string &end);
    397 
    398         /** Construct a value greater-than-or-equal query on a document value.
    399          */
    400         Internal(op_t op_, Xapian::valueno valno, const std::string &value);
    401 
    402         /// Construct an external source query.
    403         explicit Internal(Xapian::PostingSource * external_source_);
    404 
    405         /** Destructor. */
    406         ~Internal();
    407 
    408         static Xapian::Query::Internal * unserialise(const std::string &s);
    409 
    410         /** Add a subquery.
    411          */
    412         void add_subquery(const Query::Internal * subq);
    413 
    414         void set_dbl_parameter(double dbl_parameter_);
    415 
    416         double get_dbl_parameter() const;
    417 
    418         /** Finish off the construction.
    419          */
    420         Query::Internal * end_construction();
    421 
    422         /** Return a string in an easily parsed form
    423          *  which contains all the information in a query.
    424          */
    425         std::string serialise() const {
    426             Xapian::termpos curpos = 1;
    427             return serialise(curpos);
    428         }
    429 
    430         /// Return a string describing this object.
    431         std::string get_description() const;
    432 
    433         /** Get the numeric parameter used in this query.
    434          *
    435          *  This is used by the QueryParser to get the value number for
    436          *  VALUE_RANGE queries.  It should be replaced by a public method on
    437          *  the Query class at some point, but the API which should be used for
    438          *  that is unclear, so this is a temporary workaround.
    439          */
    440         Xapian::termcount get_parameter() const { return parameter; }
    441 
    442         /** Get the length of the query, used by some ranking formulae.
    443          *  This value is calculated automatically - if you want to override
    444          *  it you can pass a different value to Enquire::set_query().
    445          */
    446         Xapian::termcount get_length() const;
    447 
    448         /** Return an iterator over all the terms in the query,
    449          *  in order of termpos.  If multiple terms have the same term
    450          *  position, their order is unspecified.  Duplicates (same term and
    451          *  termpos) will be removed.
    452          */
    453         TermIterator get_terms() const;
    454 };
    455 
    456 #endif // SWIG
    457 
    458269}
    459270
    460271#endif /* XAPIAN_INCLUDED_QUERY_H */
  • common/omqueryinternal.h

     
    2424// because of the templated members of Xapian::Query.
    2525#include <xapian/query.h>
    2626
     27class LocalSubMatch;
     28class MultiMatch;
     29class QueryOptimiser;
     30struct SortPosName;
     31
     32namespace Xapian {
     33
     34/// @internal Internal class, implementing most of Xapian::Query.
     35class XAPIAN_VISIBILITY_DEFAULT Query::Internal : public Xapian::Internal::RefCntBase {
     36    friend class ::LocalSubMatch;
     37    friend class ::MultiMatch;
     38    friend class ::QueryOptimiser;
     39    friend struct ::SortPosName;
     40    friend class Query;
     41    public:
     42        static const int OP_LEAF = -1;
     43        static const int OP_EXTERNAL_SOURCE = -2;
     44
     45        /// The container type for storing pointers to subqueries
     46        typedef std::vector<Internal *> subquery_list;
     47
     48        /// Type storing the operation
     49        typedef int op_t;
     50
     51    private:
     52        /// Operation to be performed at this node
     53        Xapian::Query::Internal::op_t op;
     54
     55        /// Sub queries on which to perform operation
     56        subquery_list subqs;
     57
     58        /** For NEAR or PHRASE, how close terms must be to match: all terms
     59         *  within the operation must occur in a window of this size.
     60         *
     61         * For ELITE_SET, the number of terms to select from those specified.
     62         *
     63         * For RANGE, the value number to apply the range test to.
     64         */
     65        Xapian::termcount parameter;
     66
     67        /** Term that this node represents, or start of a range query.
     68         *
     69         *  For a leaf node, this holds the term name.  For an OP_VALUE_RANGE
     70         *  query this holds the start of the range.  For an OP_VALUE_GE or
     71         *  OP_VALUE_LE query this holds the value to compare against.
     72         */
     73        std::string tname;
     74
     75        /** Used to store the end of a range query. */
     76        std::string str_parameter;
     77
     78        /// Position in query of this term - leaf node only
     79        Xapian::termpos term_pos;
     80
     81        /// Within query frequency of this term - leaf node only
     82        Xapian::termcount wqf;
     83
     84        /// External posting source.
     85        Xapian::PostingSource * external_source;
     86
     87        /** swap the contents of this with another Xapian::Query::Internal,
     88         *  in a way which is guaranteed not to throw.  This is
     89         *  used with the assignment operator to make it exception
     90         *  safe.
     91         *  It's important to adjust swap with any addition of
     92         *  member variables!
     93         */
     94        void swap(Query::Internal &other);
     95
     96        /// Copy another Xapian::Query::Internal into self.
     97        void initialise_from_copy(const Query::Internal & copyme);
     98
     99        void accumulate_terms(
     100            std::vector<std::pair<std::string, Xapian::termpos> > &terms) const;
     101
     102        /** Simplify the query.
     103         *  For example, an AND query with only one subquery would become the
     104         *  subquery itself.
     105         */
     106        Internal * simplify_query();
     107
     108        /** Perform checks that query is valid. (eg, has correct number of
     109         *  sub queries.)  Throw an exception if not.  This is initially called
     110         *  on the query before any simplifications have been made, and after
     111         *  simplications.
     112         */
     113        void validate_query() const;
     114
     115        /** Simplify any matchnothing subqueries, either eliminating them,
     116         *  or setting this query to matchnothing, depending on the query
     117         *  operator.  Returns true if simplification resulted in a
     118         *  matchnothing query.
     119         */
     120        bool simplify_matchnothing();
     121
     122        /** Get a string describing the given query type.
     123         */
     124        static std::string get_op_name(Xapian::Query::Internal::op_t op);
     125
     126        /** Collapse the subqueries together if appropriate.
     127         */
     128        void collapse_subqs();
     129
     130        /** Flatten a query structure, by changing, for example,
     131         *  "A NEAR (B AND C)" to "(A NEAR B) AND (A NEAR C)"
     132         */
     133        void flatten_subqs();
     134
     135        /** Implementation of serialisation; called recursively.
     136         */
     137        std::string serialise(Xapian::termpos & curpos) const;
     138
     139    public:
     140        /** Copy constructor. */
     141        Internal(const Query::Internal & copyme);
     142
     143        /** Assignment. */
     144        void operator=(const Query::Internal & copyme);
     145
     146        /** A query consisting of a single term. */
     147        explicit Internal(const std::string & tname_, Xapian::termcount wqf_ = 1,
     148                          Xapian::termpos term_pos_ = 0);
     149
     150        /** Create internals given only the operator and a parameter. */
     151        Internal(op_t op_, Xapian::termcount parameter);
     152
     153        /** Construct a range query on a document value. */
     154        Internal(op_t op_, Xapian::valueno valno,
     155                 const std::string &begin, const std::string &end);
     156
     157        /** Construct a value greater-than-or-equal query on a document value.
     158         */
     159        Internal(op_t op_, Xapian::valueno valno, const std::string &value);
     160
     161        /// Construct an external source query.
     162        explicit Internal(Xapian::PostingSource * external_source_);
     163
     164        /** Destructor. */
     165        ~Internal();
     166
     167        static Xapian::Query::Internal * unserialise(const std::string &s);
     168
     169        /** Add a subquery.
     170         */
     171        void add_subquery(const Query::Internal * subq);
     172
     173        void set_dbl_parameter(double dbl_parameter_);
     174
     175        double get_dbl_parameter() const;
     176
     177        /** Finish off the construction.
     178         */
     179        Query::Internal * end_construction();
     180
     181        /** Return a string in an easily parsed form
     182         *  which contains all the information in a query.
     183         */
     184        std::string serialise() const {
     185            Xapian::termpos curpos = 1;
     186            return serialise(curpos);
     187        }
     188
     189        /// Return a string describing this object.
     190        std::string get_description() const;
     191
     192        /** Get the numeric parameter used in this query.
     193         *
     194         *  This is used by the QueryParser to get the value number for
     195         *  VALUE_RANGE queries.  It should be replaced by a public method on
     196         *  the Query class at some point, but the API which should be used for
     197         *  that is unclear, so this is a temporary workaround.
     198         */
     199        Xapian::termcount get_parameter() const { return parameter; }
     200
     201        /** Get the length of the query, used by some ranking formulae.
     202         *  This value is calculated automatically - if you want to override
     203         *  it you can pass a different value to Enquire::set_query().
     204         */
     205        Xapian::termcount get_length() const;
     206
     207        /** Return an iterator over all the terms in the query,
     208         *  in order of termpos.  If multiple terms have the same term
     209         *  position, their order is unspecified.  Duplicates (same term and
     210         *  termpos) will be removed.
     211         */
     212        TermIterator get_terms() const;
     213};
     214
     215struct XAPIAN_VISIBILITY_DEFAULT Query::InternalPtr {
     216    Xapian::Internal::RefCntPtr<Query::Internal> ptr;
     217
     218    InternalPtr() : ptr(0) {}
     219    ~InternalPtr() { ptr = 0; }
     220    Query::Internal * get() const { return ptr.get(); }
     221};
     222
     223}
     224
    27225#endif // XAPIAN_INCLUDED_OMQUERYINTERNAL_H
  • api/omquery.cc

     
    4545Query::add_subquery(const Query & subq)
    4646{
    4747    DEBUGAPICALL(void, "Xapian::Query::add_subquery", subq);
    48     Assert(internal.get());
    49     internal->add_subquery(subq.internal.get());
     48    Assert(internalptr);
     49    Assert(internalptr->get());
     50    internalptr->get()->add_subquery(subq.internalptr->get());
    5051}
    5152
    5253/// Add a subquery by pointer
     
    5758    if (subq == 0) {
    5859        throw InvalidArgumentError("Pointer to subquery may not be null");
    5960    }
    60     Assert(internal.get());
    61     internal->add_subquery(subq->internal.get());
     61    Assert(internalptr);
     62    Assert(internalptr->get());
     63    internalptr->get()->add_subquery(subq->internalptr->get());
    6264}
    6365
    6466/// Add a subquery which is a single term
     
    6668Query::add_subquery(const string & tname)
    6769{
    6870    DEBUGAPICALL(void, "Xapian::Query::add_subquery", tname);
    69     Assert(internal.get());
     71    Assert(internalptr);
     72    Assert(internalptr->get());
    7073    Query::Internal subqint(tname);
    71     internal->add_subquery(&subqint);
     74    internalptr->ptr->add_subquery(&subqint);
    7275}
    7376
    7477/// Setup the internals for the query, with the appropriate operator.
     
    7679Query::start_construction(Query::op op_, termcount parameter)
    7780{
    7881    DEBUGAPICALL(void, "Xapian::Query::start_construction", op_);
    79     Assert(!internal.get());
    80     internal = new Query::Internal(op_, parameter);
     82    Assert(!internalptr);
     83    internalptr = new Query::InternalPtr();
     84    internalptr->ptr = new Query::Internal(op_, parameter);
    8185}
    8286
    8387/// Check that query has an appropriate number of arguments, etc,
     
    8589Query::end_construction()
    8690{
    8791    DEBUGAPICALL(void, "Xapian::Query::end_construction", "");
    88     Assert(internal.get());
    89     internal = internal->end_construction();
     92    Assert(internalptr);
     93    Assert(internalptr->get());
     94    internalptr->ptr = internalptr->get()->end_construction();
    9095}
    9196
    9297/// Abort construction of the query: delete internal.
     
    9499Query::abort_construction()
    95100{
    96101    DEBUGAPICALL(void, "Xapian::Query::abort_construction", "");
    97     Assert(internal.get());
    98     internal = 0;
     102    if (internalptr) {
     103        internalptr->ptr = 0;
     104    }
    99105}
    100106
    101107Query::Query(const string & tname_, termcount wqf_, termpos pos_)
    102         : internal(new Query::Internal(tname_, wqf_, pos_))
     108        : internalptr(new Query::InternalPtr())
    103109{
    104110    DEBUGAPICALL(void, "Xapian::Query::Query",
    105111                 tname_ << ", " << wqf_ << ", " << pos_);
     112    internalptr->ptr = new Query::Internal(tname_, wqf_, pos_);
    106113}
    107114
    108115Query::Query(Query::op op_, const Query &left, const Query &right)
    109         : internal(new Query::Internal(op_, 0u))
     116        : internalptr(new Query::InternalPtr())
    110117{
    111118    DEBUGAPICALL(void, "Xapian::Query::Query",
    112119                 op_ << ", " << left << ", " << right);
     120    internalptr->ptr = new Query::Internal(op_, 0u);
    113121    try {
    114122        add_subquery(left);
    115123        add_subquery(right);
     
    125133    DEBUGAPICALL(void, "Xapian::Query::Query",
    126134                 op_ << ", " << q << ", " << parameter);
    127135    if (op_ == OP_SCALE_WEIGHT) {
    128         if (!q.internal.get() ||
    129             q.internal->op == OP_VALUE_RANGE ||
    130             q.internal->op == OP_VALUE_GE ||
    131             q.internal->op == OP_VALUE_LE) {
     136        if (!q.internalptr->get() ||
     137            q.internalptr->get()->op == OP_VALUE_RANGE ||
     138            q.internalptr->get()->op == OP_VALUE_GE ||
     139            q.internalptr->get()->op == OP_VALUE_LE) {
    132140            // Applying OP_SCALE_WEIGHT to Xapian::Query or OP_VALUE_*
    133141            // has no effect as they're all pure-boolean.
    134             internal = q.internal;
     142            Assert(!internalptr);
     143            internalptr = new Query::InternalPtr();
     144            internalptr->ptr = q.internalptr->ptr;
    135145            return;
    136146        }
    137147    }
    138148    try {
    139149        start_construction(op_, 0);
    140         internal->set_dbl_parameter(parameter);
     150        internalptr->get()->set_dbl_parameter(parameter);
    141151        add_subquery(q);
    142152        end_construction();
    143153    } catch (...) {
     
    148158
    149159Query::Query(Query::op op_, Xapian::valueno valno,
    150160             const string &begin, const string &end)
    151     : internal(new Query::Internal(op_, valno, begin, end))
     161        : internalptr(new Query::InternalPtr())
    152162{
    153163    DEBUGAPICALL(void, "Xapian::Query::Query",
    154164                 op_ << ", " << valno << ", " << begin << ", " << end);
     165    internalptr->ptr = new Query::Internal(op_, valno, begin, end);
    155166}
    156167
    157168Query::Query(Query::op op_, Xapian::valueno valno, const std::string &value)
    158     : internal(new Query::Internal(op_, valno, value))
     169        : internalptr(new Query::InternalPtr())
    159170{
    160171    DEBUGAPICALL(void, "Xapian::Query::Query",
    161172                 op_ << ", " << valno << ", " << value);
     173    internalptr->ptr = new Query::Internal(op_, valno, value);
    162174}
    163175
    164176Query::Query(PostingSource * external_source)
    165         : internal(new Query::Internal(external_source))
     177        : internalptr(new Query::InternalPtr())
    166178{
    167179    DEBUGAPICALL(void, "Xapian::Query::Query", external_source);
     180    internalptr->ptr = new Query::Internal(external_source);
    168181}
    169182
    170183// Copy constructor
    171184Query::Query(const Query & copyme)
    172         : internal(copyme.internal)
     185        : internalptr(new Query::InternalPtr())
    173186{
    174187    DEBUGAPICALL(void, "Xapian::Query::Query", copyme);
     188    internalptr->ptr = copyme.internalptr->ptr;
    175189}
    176190
    177191// Assignment
     
    179193Query::operator=(const Query & copyme)
    180194{
    181195    DEBUGAPICALL(Xapian::Query &, "Xapian::Query::operator=", copyme);
    182     internal = copyme.internal;
     196    internalptr->ptr = copyme.internalptr->ptr;
    183197    RETURN(*this);
    184198}
    185199
    186200// Default constructor
    187 Query::Query() : internal(0)
     201Query::Query() : internalptr(new Query::InternalPtr())
    188202{
    189203    DEBUGAPICALL(void, "Xapian::Query::Query", "");
    190204}
     
    193207Query::~Query()
    194208{
    195209    DEBUGAPICALL(void, "Xapian::Query::~Query", "");
     210    delete internalptr;
    196211}
    197212
    198213std::string
    199214Query::get_description() const
    200215{
    201216    std::string res("Xapian::Query(");
    202     if (internal.get()) res += internal->get_description();
     217    if (internalptr->get()) res += internalptr->get()->get_description();
    203218    res += ")";
    204219    return res;
    205220}
     
    207222termcount Query::get_length() const
    208223{
    209224    DEBUGAPICALL(Xapian::termcount, "Xapian::Query::get_length", "");
    210     RETURN(internal.get() ? internal->get_length() : 0);
     225    RETURN(internalptr->get() ? internalptr->get()->get_length() : 0);
    211226}
    212227
    213228TermIterator Query::get_terms_begin() const
    214229{
    215230    DEBUGAPICALL(Xapian::TermIterator, "Xapian::Query::get_terms_begin", "");
    216     if (!internal.get()) RETURN(TermIterator(NULL));
    217     RETURN(internal->get_terms());
     231    if (!internalptr->get()) RETURN(TermIterator(NULL));
     232    RETURN(internalptr->get()->get_terms());
    218233}
    219234
    220235bool
    221236Query::empty() const
    222237{
    223238    DEBUGAPICALL(void, "Xapian::Query::empty", "");
    224     return internal.get() == 0;
     239    return internalptr->get() == 0;
    225240}
    226241
    227242Query::Query(Query::op op_, const std::string & left, const std::string & right)
    228     : internal(0)
     243        : internalptr(0)
    229244{
    230245    try {
    231246        start_construction(op_, 0);
  • api/omenquire.cc

     
    631631    }
    632632
    633633    Stats stats;
    634     ::MultiMatch match(db, query.internal.get(), qlen, rset, collapse_key,
     634    ::MultiMatch match(db, query.internalptr->get(), qlen, rset, collapse_key,
    635635                       percent_cutoff, weight_cutoff,
    636636                       order, sort_key, sort_by, sort_value_forward, sorter,
    637637                       errorhandler, stats, weight);