Ticket #100: patch

File patch, 45.4 KB (added by Richard Boulton, 18 years ago)

Updated patch again, to apply to HEAD version 8312

  • xapian-maintainer-tools/win32msvc/win32_matcher.mak

     
    3232                 $(INTDIR)\multimatch.obj \
    3333                 $(INTDIR)\expand.obj \
    3434                 $(INTDIR)\stats.obj \
     35                 $(INTDIR)\matchcmp.obj \
    3536                 $(INTDIR)\mergepostlist.obj \
    3637                 $(INTDIR)\msetpostlist.obj \
    3738                 $(INTDIR)\msetcmp.obj \
     
    166167   $(CPP_PROJ) $**
    167168<<
    168169
     170"$(INTDIR)\matchcmp.obj" : ".\matchcmp.cc"
     171       $(CPP) @<<
     172   $(CPP_PROJ) $**
     173<<
    169174
    170175"$(INTDIR)\mergepostlist.obj" : ".\mergepostlist.cc"
    171176       $(CPP) @<<
  • xapian-core/matcher/Makefile.mk

     
    4343        matcher/expandweight.cc\
    4444        matcher/filterpostlist.cc\
    4545        matcher/localmatch.cc\
     46        matcher/matchcmp.cc\
    4647        matcher/mergepostlist.cc\
    4748        matcher/msetcmp.cc\
    4849        matcher/msetpostlist.cc\
  • xapian-core/matcher/multimatch.cc

     
    8686                       bool sort_value_forward_,
    8787                       Xapian::ErrorHandler * errorhandler_,
    8888                       StatsGatherer * gatherer_,
    89                        const Xapian::Weight * weight_)
     89                       const Xapian::Weight * weight_,
     90                       const Xapian::MatchCmp * match_cmp_)
    9091        : gatherer(gatherer_), db(db_), query(query_),
    9192          collapse_key(collapse_key_), percent_cutoff(percent_cutoff_),
    9293          weight_cutoff(weight_cutoff_), order(order_),
    9394          sort_key(sort_key_), sort_by(sort_by_),
    9495          sort_value_forward(sort_value_forward_),
    9596          errorhandler(errorhandler_), weight(weight_),
     97          match_cmp(match_cmp_),
    9698          is_remote(db.internal.size())
    9799{
    98100    DEBUGCALL(MATCH, void, "MultiMatch", db_ << ", " << query_ << ", " <<
     
    139141                is_remote[i] = true;
    140142                rem_db->set_query(query, qlen, collapse_key, order, sort_key,
    141143                                  sort_by, sort_value_forward, percent_cutoff,
    142                                   weight_cutoff, weight, subrsets[i]);
     144                                  weight_cutoff, weight, match_cmp,
     145                                  subrsets[i]);
    143146                bool decreasing_relevance =
    144147                    (sort_by == REL || sort_by == REL_VAL);
    145148                smatch = new RemoteSubMatch(rem_db, gatherer.get(),
     
    193196}
    194197
    195198string
    196 MultiMatch::get_collapse_key(PostList *pl, Xapian::docid did,
    197                              Xapian::valueno keyno, Xapian::Internal::RefCntPtr<Xapian::Document::Internal> &doc)
     199MultiMatch::get_collapse_key(PostList *pl,
     200                             Xapian::valueno keyno,
     201                             const Xapian::Internal::MSetItem & item)
    198202{
    199     DEBUGCALL(MATCH, string, "MultiMatch::get_collapse_key", pl << ", " << did << ", " << keyno << ", [doc]");
     203    DEBUGCALL(MATCH, string, "MultiMatch::get_collapse_key", pl << ", " << item.did << ", " << keyno << ", [doc]");
     204
     205    // FIXME - this gets the collapse key from the postlist.  This only
     206    // actually happens for Mset postlists (or mergepostlists containing an
     207    // mset postlist), since this is the only case where the collapse key has
     208    // been read already.  Instead, we should use the document object stored in
     209    // the mset item.
     210
    200211    const string *key = pl->get_collapse_key();
    201212    if (key) RETURN(*key);
    202     if (doc.get() == 0) {
    203         unsigned int multiplier = db.internal.size();
    204         Assert(multiplier != 0);
    205         Xapian::doccount n = (did - 1) % multiplier; // which actual database
    206         Xapian::docid m = (did - 1) / multiplier + 1; // real docid in that database
    207 
    208         Xapian::Internal::RefCntPtr<Xapian::Document::Internal> temp(db.internal[n]->open_document(m, true));
    209         doc = temp;
    210     }
    211     RETURN(doc->get_value(keyno));
     213    RETURN(item.get_document()->get_value(keyno));
    212214}
    213215
    214216Xapian::weight
     
    231233void
    232234MultiMatch::get_mset(Xapian::doccount first, Xapian::doccount maxitems,
    233235                     Xapian::doccount check_at_least,
    234                      Xapian::MSet & mset, const Xapian::MatchDecider *mdecider)
     236                     Xapian::MSet & mset,
     237                     const Xapian::MatchDecider *mdecider)
    235238{
    236239    DEBUGCALL(MATCH, void, "MultiMatch::get_mset", first << ", " << maxitems
    237240              << ", " << check_at_least << ", ...");
     
    362365
    363366    /// Comparison functor for sorting MSet
    364367    bool sort_forward = (order != Xapian::Enquire::DESCENDING);
    365     MSetCmp mcmp(get_msetcmp_function(sort_by, sort_forward, sort_value_forward));
     368    mset_cmp cmpfn = get_msetcmp_function(sort_by, sort_forward, sort_value_forward);
     369    MSetCmp mcmp(cmpfn, sort_key, match_cmp);
    366370
     371    /// Number of databases making up the database we're using.
     372    const unsigned int db_internal_size = db.internal.size();
     373    Assert(db_internal_size != 0);
     374
    367375    // Perform query
    368376
    369377    // We form the mset in two stages.  In the first we fill up our working
     
    410418        if (min_item.wt > 0.0) wt = pl->get_weight();
    411419
    412420        DEBUGLINE(MATCH, "Candidate document id " << did << " wt " << wt);
    413         Xapian::Internal::MSetItem new_item(wt, did);
    414         if (sort_by != REL) {
    415             const unsigned int multiplier = db.internal.size();
    416             Assert(multiplier != 0);
    417             Xapian::doccount n = (new_item.did - 1) % multiplier; // which actual database
    418             Xapian::docid m = (new_item.did - 1) / multiplier + 1; // real docid in that database
    419             Xapian::Internal::RefCntPtr<Xapian::Document::Internal> doc(db.internal[n]->open_document(m, true));
    420             new_item.sort_key = doc->get_value(sort_key);
    421         }
     421        Xapian::Internal::RefCntPtr<Xapian::Database::Internal> internal_db = db.internal[((did - 1) % db_internal_size)]; // database holding document
     422        Xapian::docid internal_docid = (did - 1) / db_internal_size + 1; // docid in internal_db
     423        Xapian::Internal::MSetItem new_item(wt, did, internal_db, internal_docid);
    422424
    423425        // Test if item has high enough weight (or sort key) to get into
    424426        // proto-mset.
    425427        if (sort_by != REL || min_item.wt > 0.0)
    426428            if (!mcmp(new_item, min_item)) continue;
    427429
    428         Xapian::Internal::RefCntPtr<Xapian::Document::Internal> doc;
    429 
    430430        // Use the decision functor if any.
    431431        if (mdecider != NULL) {
    432432            const unsigned int multiplier = db.internal.size();
     
    435435            // If the results are from a remote database, then the functor will
    436436            // already have been applied there so we can skip this step.
    437437            if (!is_remote[n]) {
    438                 if (doc.get() == 0) {
    439                     Xapian::docid m = (did - 1) / multiplier + 1; // real docid in that database
    440 
    441                     Xapian::Internal::RefCntPtr<Xapian::Document::Internal> temp(db.internal[n]->open_document(m, true));
    442                     doc = temp;
    443                 }
    444                 Xapian::Document mydoc(doc.get());
     438                Xapian::Document mydoc(new_item.get_document().get());
    445439                if (!mdecider->operator()(mydoc)) continue;
    446440            }
    447441        }
     
    457451
    458452        // Perform collapsing on key if requested.
    459453        if (collapse_key != Xapian::BAD_VALUENO) {
    460             new_item.collapse_key = get_collapse_key(pl, did, collapse_key,
    461                                                      doc);
     454            new_item.collapse_key = get_collapse_key(pl, collapse_key, new_item);
    462455
    463456            // Don't collapse on null key
    464457            if (!new_item.collapse_key.empty()) {
  • xapian-core/matcher/msetcmp.h

     
    2020
    2121#include "omenquireinternal.h"
    2222
     23class MSetCmp;
     24
    2325// typedef for MSetItem comparison function.
    2426typedef bool (* mset_cmp)(const Xapian::Internal::MSetItem &,
    25                           const Xapian::Internal::MSetItem &);
     27                          const Xapian::Internal::MSetItem &,
     28                          const MSetCmp *);
    2629
    2730/// Select the appropriate msetcmp function.
    2831mset_cmp get_msetcmp_function(Xapian::Enquire::Internal::sort_setting sort_by, bool sort_forward, bool sort_value_forward);
     
    3134class MSetCmp {
    3235    mset_cmp fn;
    3336  public:
    34     MSetCmp(mset_cmp fn_) : fn(fn_) { }
     37    Xapian::valueno sort_key;
     38    const Xapian::MatchCmp * cmp;
     39
     40    /// Construct an instance of MSetCmp using a built-in comparison function.
     41    MSetCmp(mset_cmp fn_,
     42            Xapian::valueno sort_key_,
     43            const Xapian::MatchCmp * cmp_)
     44        : fn(fn_), sort_key(sort_key_), cmp(cmp_) { }
     45
    3546    /// Return true if MSetItem a should be ranked above MSetItem b.
    3647    bool operator()(const Xapian::Internal::MSetItem &a,
    37                     const Xapian::Internal::MSetItem &b) const {
    38         return fn(a, b);
     48                    const Xapian::Internal::MSetItem &b) const {
     49        return fn(a, b, this);
    3950    }
    4051};
     52
  • xapian-core/matcher/msetcmp.cc

     
    2020
    2121#include <config.h>
    2222#include "msetcmp.h"
     23#include <string>
    2324
    2425/* We use templates to generate the 14 different comparison functions
    2526 * which we need.  This avoids having to write them all out by hand.
     
    4647// Order by relevance, then docid.
    4748template<bool FORWARD_DID> bool
    4849msetcmp_by_relevance(const Xapian::Internal::MSetItem &a,
    49                      const Xapian::Internal::MSetItem &b)
     50                     const Xapian::Internal::MSetItem &b,
     51                     const MSetCmp *)
    5052{
    5153    if (a.wt > b.wt) return true;
    5254    if (a.wt < b.wt) return false;
     
    5658// Order by value, then docid.
    5759template<bool FORWARD_VALUE, bool FORWARD_DID> bool
    5860msetcmp_by_value(const Xapian::Internal::MSetItem &a,
    59                  const Xapian::Internal::MSetItem &b)
     61                 const Xapian::Internal::MSetItem &b,
     62                 const MSetCmp * cmp)
    6063{
    6164    if (!FORWARD_VALUE) {
    6265        // We want dummy did 0 to compare worse than any other.
    6366        if (a.did == 0) return false;
    6467        if (b.did == 0) return true;
    6568    }
    66     if (a.sort_key > b.sort_key) return FORWARD_VALUE;
    67     if (a.sort_key < b.sort_key) return !FORWARD_VALUE;
     69    std::string sort_key_a = a.get_document()->get_value(cmp->sort_key);
     70    std::string sort_key_b = b.get_document()->get_value(cmp->sort_key);
     71    if (sort_key_a > sort_key_b) return FORWARD_VALUE;
     72    if (sort_key_a < sort_key_b) return !FORWARD_VALUE;
    6873    return msetcmp_by_did<FORWARD_DID, FORWARD_VALUE>(a, b);
    6974}
    7075
    7176// Order by value, then relevance, then docid.
    7277template<bool FORWARD_VALUE, bool FORWARD_DID> bool
    7378msetcmp_by_value_then_relevance(const Xapian::Internal::MSetItem &a,
    74                                 const Xapian::Internal::MSetItem &b)
     79                                const Xapian::Internal::MSetItem &b,
     80                                const MSetCmp * cmp)
    7581{
    7682    if (!FORWARD_VALUE) {
    7783        // two special cases to make min_item compares work when did == 0
    7884        if (a.did == 0) return false;
    7985        if (b.did == 0) return true;
    8086    }
    81     if (a.sort_key > b.sort_key) return FORWARD_VALUE;
    82     if (a.sort_key < b.sort_key) return !FORWARD_VALUE;
     87    std::string sort_key_a = a.get_document()->get_value(cmp->sort_key);
     88    std::string sort_key_b = b.get_document()->get_value(cmp->sort_key);
     89    if (sort_key_a > sort_key_b) return FORWARD_VALUE;
     90    if (sort_key_a < sort_key_b) return !FORWARD_VALUE;
    8391    if (a.wt > b.wt) return true;
    8492    if (a.wt < b.wt) return false;
    8593    return msetcmp_by_did<FORWARD_DID, FORWARD_VALUE>(a, b);
     
    8896// Order by relevance, then value, then docid.
    8997template<bool FORWARD_VALUE, bool FORWARD_DID> bool
    9098msetcmp_by_relevance_then_value(const Xapian::Internal::MSetItem &a,
    91                                 const Xapian::Internal::MSetItem &b)
     99                                const Xapian::Internal::MSetItem &b,
     100                                const MSetCmp * cmp)
    92101{
    93102    if (!FORWARD_VALUE) {
    94103        // two special cases to make min_item compares work when did == 0
     
    97106    }
    98107    if (a.wt > b.wt) return true;
    99108    if (a.wt < b.wt) return false;
    100     if (a.sort_key > b.sort_key) return FORWARD_VALUE;
    101     if (a.sort_key < b.sort_key) return !FORWARD_VALUE;
     109    std::string sort_key_a = a.get_document()->get_value(cmp->sort_key);
     110    std::string sort_key_b = b.get_document()->get_value(cmp->sort_key);
     111    if (sort_key_a > sort_key_b) return FORWARD_VALUE;
     112    if (sort_key_a < sort_key_b) return !FORWARD_VALUE;
    102113    return msetcmp_by_did<FORWARD_DID, FORWARD_VALUE>(a, b);
    103114}
    104115
     116template<bool FORWARD_DID> bool
     117msetcmp_by_user_cmpfn(const Xapian::Internal::MSetItem &a,
     118                      const Xapian::Internal::MSetItem &b,
     119                      const MSetCmp * cmp)
     120{
     121    // We want dummy did 0 to compare worse than any other.
     122    if (a.did == 0) return false;
     123    if (b.did == 0) return true;
     124
     125    if (a.did == b.did) return false; // FIXME - can this ever happen?  If not, convert this to Assert(a.did != b.did).
     126    Xapian::MatchItem item_a(a);
     127    Xapian::MatchItem item_b(b);
     128    int c = (cmp->cmp->cmp)(item_a, item_b);
     129    if (c < 0)
     130        return true;
     131    else if (c > 0)
     132        return false;
     133    if (FORWARD_DID) {
     134        return (a.did < b.did);
     135    } else {
     136        return (a.did > b.did);
     137    }
     138}
     139
    105140static mset_cmp mset_cmp_table[] = {
    106141    // Xapian::Enquire::Internal::REL
    107142    msetcmp_by_relevance<false>,
     
    122157    msetcmp_by_relevance_then_value<true, true>,
    123158    msetcmp_by_relevance_then_value<false, true>,
    124159    msetcmp_by_relevance_then_value<true, false>,
    125     msetcmp_by_relevance_then_value<false, false>
     160    msetcmp_by_relevance_then_value<false, false>,
     161    // Xapian::Enquire::Internal::USER
     162    msetcmp_by_user_cmpfn<false>,
     163    msetcmp_by_user_cmpfn<false>,
     164    msetcmp_by_user_cmpfn<true>,
     165    msetcmp_by_user_cmpfn<true>
    126166};
    127167
    128168mset_cmp get_msetcmp_function(Xapian::Enquire::Internal::sort_setting sort_by, bool sort_forward, bool sort_value_forward) {
  • xapian-core/tests/internaltest.cc

     
    385385        255.5,
    386386        256.125,
    387387        257.03125,
     388        0.12268031290495594321l,
     389        0.12268031290495592933l,
    388390    };
    389391
    390392    check_double_serialisation(0.0);
  • xapian-core/tests/api_db.cc

     
    12641264// set_sort_by_value
    12651265// set_sort_by_value_then_relevance
    12661266// set_sort_by_relevance_then_value
     1267// User comparison functions
    12671268static bool test_sortrel1()
    12681269{
    12691270    Xapian::Enquire enquire(get_database("apitest_sortrel"));
     
    12791280    const Xapian::docid order7[] = { 7,9,8,6,5,4,2,1,3 };
    12801281    const Xapian::docid order8[] = { 7,6,2,9,5,1,8,4,3 };
    12811282    const Xapian::docid order9[] = { 2,6,7,1,5,9,3,4,8 };
     1283    const Xapian::docid order10[] = { 7,9,4,5,6,1,2,3,8 };
     1284    const Xapian::docid order11[] = { 8,1,2,3,4,5,6,7,9 };
     1285    const Xapian::docid order12[] = { 9,7,6,5,4,3,2,1,8 };
     1286    const Xapian::docid order13[] = { 8,3,2,1,6,5,4,9,7 };
    12821287
    12831288    Xapian::MSet mset;
    12841289    size_t i;
     
    12891294        TEST_EQUAL(*mset[i], order1[i]);
    12901295    }
    12911296
     1297    enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100));
     1298
     1299    mset = enquire.get_mset(0, 10);
     1300    TEST_EQUAL(mset.size(), sizeof(order10) / sizeof(Xapian::docid));
     1301    for (i = 0; i < sizeof(order10) / sizeof(Xapian::docid); ++i) {
     1302        TEST_EQUAL(*mset[i], order10[i]);
     1303    }
     1304
     1305    enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100, true));
     1306
     1307    mset = enquire.get_mset(0, 10);
     1308    TEST_EQUAL(mset.size(), sizeof(order10) / sizeof(Xapian::docid));
     1309    for (i = 0; i < sizeof(order10) / sizeof(Xapian::docid); ++i) {
     1310        TEST_EQUAL(*mset[i], order10[i]);
     1311    }
     1312
     1313    enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100, false));
     1314
     1315    mset = enquire.get_mset(0, 10);
     1316    TEST_EQUAL(mset.size(), sizeof(order11) / sizeof(Xapian::docid));
     1317    for (i = 0; i < sizeof(order11) / sizeof(Xapian::docid); ++i) {
     1318        TEST_EQUAL(*mset[i], order11[i]);
     1319    }
     1320
    12921321    enquire.set_sort_by_value_then_relevance(1);
    12931322
    12941323    mset = enquire.get_mset(0, 10);
     
    13051334        TEST_EQUAL(*mset[i], order1[i]);
    13061335    }
    13071336
     1337    enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100));
     1338    enquire.set_docid_order(Xapian::Enquire::DESCENDING);
     1339
     1340    mset = enquire.get_mset(0, 10);
     1341    TEST_EQUAL(mset.size(), sizeof(order12) / sizeof(Xapian::docid));
     1342    for (i = 0; i < sizeof(order12) / sizeof(Xapian::docid); ++i) {
     1343        TEST_EQUAL(*mset[i], order12[i]);
     1344    }
     1345
     1346    enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100, true));
     1347    enquire.set_docid_order(Xapian::Enquire::DESCENDING);
     1348
     1349    mset = enquire.get_mset(0, 10);
     1350    TEST_EQUAL(mset.size(), sizeof(order12) / sizeof(Xapian::docid));
     1351    for (i = 0; i < sizeof(order12) / sizeof(Xapian::docid); ++i) {
     1352        TEST_EQUAL(*mset[i], order12[i]);
     1353    }
     1354
     1355    enquire.set_sort_by_cmpfn(Xapian::IntegerMatchCmp(100, false));
     1356    enquire.set_docid_order(Xapian::Enquire::DESCENDING);
     1357
     1358    mset = enquire.get_mset(0, 10);
     1359    TEST_EQUAL(mset.size(), sizeof(order13) / sizeof(Xapian::docid));
     1360    for (i = 0; i < sizeof(order13) / sizeof(Xapian::docid); ++i) {
     1361        TEST_EQUAL(*mset[i], order13[i]);
     1362    }
     1363
    13081364    enquire.set_sort_by_value_then_relevance(1);
    13091365    enquire.set_docid_order(Xapian::Enquire::DESCENDING);
    13101366
  • xapian-core/tests/harness/index_utils.cc

     
    7878    for (Xapian::valueno i = min(para.length(), size_t(10)); i >= 1; --i) {
    7979        doc.add_value(i, para.substr(i, 1));
    8080    }
     81    if (para.length() > 1 && para[0] == 'V') {
     82        doc.add_value(100, Xapian::IntegerMatchCmp::int_to_value(atoi(para.c_str() + 1)));
     83    }
    8184
    8285    Xapian::termcount pos = 0;
    8386    string::const_iterator end = para.begin();
  • xapian-core/tests/testdata/apitest_sortrel.txt

     
    1212
    1313V1 woman
    1414
    15 V1 man woman fish
     15V10 man woman fish
    1616
    1717V1 man woman
  • xapian-core/include/xapian/enquire.h

     
    3131#include <xapian/types.h>
    3232#include <xapian/termiterator.h>
    3333#include <xapian/visibility.h>
     34#include <xapian/document.h>
    3435
    3536namespace Xapian {
    3637
     
    4041class MSetIterator;
    4142class Query;
    4243class Weight;
     44class MatchCmp;
    4345
     46namespace Internal {
     47    class MSetItem;
     48}
     49
    4450/** A match set (MSet).
    4551 *  This class represents (a portion of) the results of a query.
    4652 */
     
    812818        void set_sort_by_relevance_then_value(Xapian::valueno sort_key,
    813819                                              bool ascending = true);
    814820
     821        /** Set a comparison functor to be used when comparing matches.
     822         *
     823         *  This overrides the sort options set by set_sort_by_relevance(),
     824         *  set_sort_by_value(), set_sort_by_relevance_then_value() and
     825         *  set_sort_by_value_then_relevance().  For matches which the
     826         *  comparison functor considers equal (ie, for which the functor
     827         *  returns 0 when comparing them), the matches will be compared in
     828         *  document ID order, as set by set_docid_order();
     829         *
     830         *  The comparison function will be called many times in the process of
     831         *  performing the search.  Therefore, it is important that it is
     832         *  implemented as efficiently as possible.
     833         *
     834         *  @param cmpfn_ The comparion function to use to compare matches.
     835         */
     836        void set_sort_by_cmpfn(const MatchCmp &cmpfn_);
     837
    815838        /** Get (a portion of) the match set for the current query.
    816839         *
    817840         *  @param first     the first item in the result set to return.
     
    12201243        bool get_sumpart_needs_doclength() const;
    12211244};
    12221245
     1246/// An item matching a search.
     1247class XAPIAN_VISIBILITY_DEFAULT MatchItem {
     1248    private:
     1249        const Xapian::Internal::MSetItem & item;
     1250
     1251    public:
     1252        MatchItem(const Xapian::Internal::MSetItem & item_)
     1253            : item(item_) {}
     1254
     1255        /** Get the weight calculated. */
     1256        Xapian::weight get_wt() const;
     1257
     1258        /** Get the document id. */
     1259        Xapian::docid get_docid() const;
     1260
     1261        /** Get the document object, for access to document data, values,
     1262         *  and terms. */
     1263        Xapian::Document get_document() const;
     1264};
     1265
     1266/// Abstract base class for match comparison functors.
     1267class XAPIAN_VISIBILITY_DEFAULT MatchCmp {
     1268    friend class Enquire; // So Enquire can clone us
     1269    friend class ::RemoteServer; // So RemoteServer can clone us - FIXME
     1270    protected:
     1271        MatchCmp(const MatchCmp &);
     1272    private:
     1273        void operator=(MatchCmp &);
     1274
     1275        /** Return a new MatchCmp object of this type.
     1276         *
     1277         * A subclass called FooMatchCmp taking parameters param1 and param2
     1278         * should implement this as:
     1279         *
     1280         * virtual FooMatchCmp * clone() const {
     1281         *     return new FooMatchCmp(param1, param2);
     1282         * }
     1283         */
     1284        virtual MatchCmp * clone() const = 0;
     1285
     1286    public:
     1287        MatchCmp() { }
     1288        virtual ~MatchCmp() { }
     1289
     1290        /** Name of the comparison functor.
     1291         *
     1292         *  If the subclass is called FooMatchCmp, this should return "Foo".
     1293         */
     1294        virtual std::string name() const = 0;
     1295
     1296        /// Serialise object parameters into a string.
     1297        virtual std::string serialise() const = 0;
     1298
     1299        /** Create object given string serialisation returned by serialise().
     1300         *
     1301         *  If the string is not a valid serialised form, this should raise a
     1302         *  Xapian::NetworkError;
     1303         */
     1304        virtual MatchCmp * unserialise(const std::string &s) const = 0;
     1305
     1306        /** Compare a potential Mset entry a to an entry b.
     1307         *
     1308         *  This function should return an integer less than 0 if MatchItem a
     1309         *  should be ranked below MatchItem b, and greater than 0 if MatchItem
     1310         *  a should be ranked above MatchItem b.  The function may return 0 if
     1311         *  it considers the two match items to be equal.
     1312         *
     1313         *  The function will never be called with items which have identical
     1314         *  document IDs.
     1315         *
     1316         *  The comparison function must be well behaved, such that:
     1317         *
     1318         *   - it must produce the same result if called a second time on a
     1319         *     particular pair of documents
     1320         *   - if cmp(x,y) is less than 0 and cmp(y,z) is less than 0, cmp(x,z)
     1321         *     must be less than 0.
     1322         *   - if cmp(x,y) is less than 0, cmp(y,x) must be greater than 0.
     1323         *
     1324         *  Bear in mind that the comparison will be performed very frequently
     1325         *  when performing a search, so must be as fast as possible.  In
     1326         *  particular, although the MatchItem provides access to the document
     1327         *  object, it is recommended that only the value items stored in the
     1328         *  document object are accessed.
     1329         */
     1330        virtual int cmp(const MatchItem & a,
     1331                        const MatchItem & b) const = 0;
     1332};
     1333
     1334/** Comparison function for comparing by value as integer.
     1335 */
     1336class XAPIAN_VISIBILITY_DEFAULT IntegerMatchCmp : public MatchCmp {
     1337        Xapian::valueno sort_key;
     1338        int direction;
     1339    public:
     1340        /** Return a new IntegerMatchCmp with the same parameters as this one.
     1341         */
     1342        IntegerMatchCmp * clone() const {
     1343            return new IntegerMatchCmp(sort_key, direction == 1);
     1344        }
     1345        IntegerMatchCmp(Xapian::valueno sort_key_,
     1346                        bool ascending = true)
     1347                : sort_key(sort_key_),
     1348                  direction(ascending ? 1 : -1) { }
     1349        IntegerMatchCmp()
     1350                : sort_key(0),
     1351                  direction(1) { }
     1352        ~IntegerMatchCmp() { }
     1353        std::string name() const { return "Integer"; }
     1354
     1355        std::string serialise() const;
     1356        IntegerMatchCmp * unserialise(const std::string &s) const;
     1357
     1358        int cmp(const MatchItem & a,
     1359                const MatchItem & b) const;
     1360
     1361        /** Convert an integer to a string, suitable for comparing with this
     1362         *  comparison functor.
     1363         */
     1364        static std::string int_to_value(int num);
     1365
     1366        /** Convert a string suitable for comparison with this comparison
     1367         *  functor to an integer.
     1368         */
     1369        static int value_to_int(const std::string &s);
     1370};
     1371
     1372/** Comparison function for comparing by value as a double.
     1373 */
     1374class XAPIAN_VISIBILITY_DEFAULT DoubleMatchCmp : public MatchCmp {
     1375        Xapian::valueno sort_key;
     1376        int direction;
     1377    public:
     1378        /** Return a new DoubleMatchCmp with the same parameters as this one.
     1379         */
     1380        DoubleMatchCmp * clone() const {
     1381            return new DoubleMatchCmp(sort_key, direction == 1);
     1382        }
     1383        DoubleMatchCmp(Xapian::valueno sort_key_,
     1384                       bool ascending = true)
     1385                : sort_key(sort_key_),
     1386                  direction(ascending ? 1 : -1) { }
     1387        DoubleMatchCmp()
     1388                : sort_key(0),
     1389                  direction(1) { }
     1390        ~DoubleMatchCmp() { }
     1391        std::string name() const { return "Double"; }
     1392
     1393        std::string serialise() const;
     1394        DoubleMatchCmp * unserialise(const std::string &s) const;
     1395
     1396        int cmp(const MatchItem & a,
     1397                const MatchItem & b) const;
     1398
     1399        /** Convert a double to a string, suitable for comparing with this
     1400         *  comparison functor.
     1401         */
     1402        static std::string double_to_value(double num);
     1403
     1404        /** Convert a string suitable for comparison with this comparison
     1405         *  functor to a double.
     1406         */
     1407        static double value_to_double(const std::string &s);
     1408};
     1409
    12231410}
    12241411
    12251412#endif /* XAPIAN_INCLUDED_ENQUIRE_H */
  • xapian-core/net/serialise.cc

     
    223223}
    224224
    225225Xapian::MSet
    226 unserialise_mset(const string &s)
     226unserialise_mset(const string &s,
     227                 Xapian::Internal::RefCntPtr<Xapian::Database::Internal> internal_db)
    227228{
    228229    const char * p = s.data();
    229230    const char * p_end = p + s.size();
     
    242243        size_t len = decode_length(&p, p_end, true);
    243244        string key(p, len);
    244245        p += len;
    245         items.push_back(Xapian::Internal::MSetItem(wt, did, key,
     246        items.push_back(Xapian::Internal::MSetItem(wt, did,
     247                                                   internal_db,
     248                                                   did,
     249                                                   key,
    246250                                                   decode_length(&p, p_end, false)));
    247251    }
    248252
  • xapian-core/net/remoteserver.cc

     
    9090    wtschemes[weight->name()] = weight;
    9191    weight = new Xapian::TradWeight();
    9292    wtschemes[weight->name()] = weight;
     93
     94    // Register match comparison functions.
     95    Xapian::MatchCmp * match_cmp;
     96    match_cmp = new Xapian::IntegerMatchCmp();
     97    match_cmps[match_cmp->name()] = match_cmp;
     98    match_cmp = new Xapian::DoubleMatchCmp();
     99    match_cmps[match_cmp->name()] = match_cmp;
    93100}
    94101
    95102RemoteServer::~RemoteServer()
     
    98105    for (i = wtschemes.begin(); i != wtschemes.end(); ++i) {
    99106        delete i->second;
    100107    }
     108    map<string, Xapian::MatchCmp*>::const_iterator j;
     109    for (j = match_cmps.begin(); j != match_cmps.end(); ++j) {
     110        delete j->second;
     111    }
    101112}
    102113
    103114message_type
     
    322333
    323334    Xapian::valueno sort_key = decode_length(&p, p_end, false);
    324335
    325     if (*p < '0' || *p > '3') {
     336    if (*p < '0' || *p > '4') {
    326337        throw Xapian::NetworkError("bad message (sort_by)");
    327338    }
    328339    Xapian::Enquire::Internal::sort_setting sort_by;
     
    356367    AutoPtr<Xapian::Weight> wt(i->second->unserialise(string(p, len)));
    357368    p += len;
    358369
     370    // Unserialise the MatchCmp object
     371    len = decode_length(&p, p_end, true);
     372    AutoPtr<Xapian::MatchCmp> mcmp;
     373    if (len > 0) {
     374        map<string, Xapian::MatchCmp *>::const_iterator j;
     375        j = match_cmps.find(string(p, len));
     376        if (j == match_cmps.end()) {
     377            throw Xapian::InvalidArgumentError("MatchCmp type " + string(p, len) + " not registered");
     378        }
     379        p += len;
     380
     381        len = decode_length(&p, p_end, true);
     382        mcmp = j->second->unserialise(string(p, len));
     383        p += len;
     384    }
     385
    359386    // Unserialise the RSet object.
    360387    Xapian::RSet rset = unserialise_rset(string(p, p_end - p));
    361388
     
    364391    MultiMatch match(*db, query.get(), qlen, rset, collapse_key,
    365392                     percent_cutoff, weight_cutoff, order,
    366393                     sort_key, sort_by, sort_value_forward,
    367                      NULL, gatherer, wt.get());
     394                     NULL, gatherer, wt.get(), mcmp.get());
    368395
    369396    send_message(REPLY_STATS, serialise_stats(gatherer->get_local_stats()));
    370397
  • xapian-core/common/remote-database.h

     
    124124     * @param percent_cutoff            Percentage cutoff.
    125125     * @param weight_cutoff             Weight cutoff.
    126126     * @param wtscheme                  Weighting scheme.
     127     * @param sort_cmpfn                Comparison functor for sorting.
    127128     * @param omrset                    The rset.
    128129     */
    129130    void set_query(const Xapian::Query::Internal *query,
     
    135136                   bool sort_value_forward,
    136137                   int percent_cutoff, Xapian::weight weight_cutoff,
    137138                   const Xapian::Weight *wtscheme,
     139                   const Xapian::MatchCmp *sort_cmpfn,
    138140                   const Xapian::RSet &omrset);
    139141
    140142    /** Get the Stats from the remote server.
  • xapian-core/common/omenquireinternal.h

     
    3131#include <math.h>
    3232#include <map>
    3333#include <set>
     34#include "document.h"
    3435
    3536using namespace std;
    3637
     
    6465};
    6566
    6667/** An item resulting from a query.
     68 *
    6769 *  This item contains the document id, and the weight calculated for
    6870 *  the document.
     71 *
     72 *  It also provides access to the underlying document,
     73 *  and stores information needed to support collapse operations.
    6974 */
    7075class MSetItem {
    7176    public:
    7277        MSetItem(Xapian::weight wt_, Xapian::docid did_)
    73                 : wt(wt_), did(did_), collapse_count(0) {}
     78                : wt(wt_),
     79                  did(did_),
     80                  collapse_count(0),
     81                  internal_docid(0) {}
    7482
    75         MSetItem(Xapian::weight wt_, Xapian::docid did_, const string &key_)
    76                 : wt(wt_), did(did_), collapse_key(key_), collapse_count(0) {}
     83        MSetItem(Xapian::weight wt_,
     84                 Xapian::docid did_,
     85                 const Xapian::Internal::RefCntPtr<Xapian::Database::Internal> & internal_db_,
     86                 Xapian::docid internal_docid_)
     87                : wt(wt_),
     88                  did(did_),
     89                  collapse_count(0),
     90                  internal_db(internal_db_),
     91                  internal_docid(internal_docid_) {}
    7792
    78         MSetItem(Xapian::weight wt_, Xapian::docid did_, const string &key_,
     93        MSetItem(Xapian::weight wt_,
     94                 Xapian::docid did_,
     95                 const Xapian::Internal::RefCntPtr<Xapian::Database::Internal> & internal_db_,
     96                 Xapian::docid internal_docid_,
     97                 const string &collapse_key_,
    7998                 Xapian::doccount collapse_count_)
    80                 : wt(wt_), did(did_), collapse_key(key_),
    81                   collapse_count(collapse_count_) {}
     99                : wt(wt_),
     100                  did(did_),
     101                  collapse_key(collapse_key_),
     102                  collapse_count(collapse_count_),
     103                  internal_db(internal_db_),
     104                  internal_docid(internal_docid_) {}
    82105
    83106        /** Weight calculated. */
    84107        Xapian::weight wt;
    85108
    86         /** Document id. */
     109        /** Document id (as publically displayed). */
    87110        Xapian::docid did;
    88111
    89112        /** Value which was used to collapse upon.
     
    96119         *  for this item, the value will be a null string.  Only one instance
    97120         *  of each key value (apart from the null string) will be present in
    98121         *  the items in the returned Xapian::MSet.
     122         *
     123         *  FIXME - just use doc.
    99124         */
    100125        string collapse_key;
    101126
    102         /** Count of collapses done on collapse_key so far
     127        /** Count of collapses done on collapse_key so far.
    103128         *
    104          * This is normally 0, and goes up for each collapse done
    105          * It is not neccessarily an indication of how many collapses
    106          * might be done if an exhaustive match was done
     129         *  This is normally 0, and goes up for each collapse done
     130         *  It is not neccessarily an indication of how many collapses
     131         *  might be done if an exhaustive match was done
    107132         */
    108133        Xapian::doccount collapse_count;
    109134
    110         /** Used when sorting by value. */
    111         /* FIXME: why not just cache the Xapian::Document here!?! */
    112         string sort_key;
     135        /** Get the document.
     136         *
     137         *  This will cache the document from previous requests, and will
     138         *  return a pointer to NULL if the MSetItem was not initialised with
     139         *  and internal_db and internal_docid.
     140         */
     141        const Xapian::Internal::RefCntPtr<Xapian::Document::Internal> &
     142        get_document() const
     143        {
     144            if (doc.get() == NULL)
     145            {
     146                if (internal_db.get() == NULL)
     147                {
     148                    Xapian::Internal::RefCntPtr<Xapian::Document::Internal> temp(new Xapian::Document::Internal());
     149                    doc = temp;
     150                } else {
     151                    Xapian::Internal::RefCntPtr<Xapian::Document::Internal> temp(internal_db->open_document(internal_docid, true));
     152                    doc = temp;
     153                }
     154            }
     155            return doc;
     156        }
    113157
    114158        /** Returns a string representing the mset item.
    115159         *  Introspection method.
    116160         */
    117161        string get_description() const;
     162
     163    private:
     164        /** Database containing the document. */
     165        Xapian::Internal::RefCntPtr<Xapian::Database::Internal> internal_db;
     166
     167        /** Document id in database containing the document. */
     168        Xapian::docid internal_docid;
     169
     170        /** Document object.  Points to NULL before the document has
     171         *  been requested (with get_document()). */
     172        mutable Xapian::Internal::RefCntPtr<Xapian::Document::Internal> doc;
    118173};
    119174
    120175}
     
    140195        void operator=(const Internal &);
    141196
    142197    public:
    143         typedef enum { REL, VAL, VAL_REL, REL_VAL } sort_setting;
     198        typedef enum { REL, VAL, VAL_REL, REL_VAL, USER } sort_setting;
    144199
    145200        Xapian::valueno collapse_key;
    146201
     
    153208        Xapian::valueno sort_key;
    154209        sort_setting sort_by;
    155210        bool sort_value_forward;
     211        MatchCmp * sort_cmpfn;
    156212
    157213        /** The error handler, if set.  (0 if not set).
    158214         */
  • xapian-core/common/multimatch.h

     
    6464        /// Weighting scheme
    6565        const Xapian::Weight * weight;
    6666
     67        /// User supplied match comparison function
     68        const Xapian::MatchCmp * match_cmp;
     69
    6770        /** Internal flag to note that w_max needs to be recalculated
    6871         *  while query is running.
    6972         */
     
    7477
    7578        /// get the collapse key
    7679        string get_collapse_key(PostList *pl,
    77                                 Xapian::docid did, Xapian::valueno keyno,
    78                                 Xapian::Internal::RefCntPtr<Xapian::Document::Internal> &doc);
     80                                Xapian::valueno keyno,
     81                                const Xapian::Internal::MSetItem & item);
    7982
    8083        /** get the maxweight that the postlist pl may return, calling
    8184         *  recalc_maxweight if recalculate_w_max is set, and unsetting it.
     
    115118                   bool sort_value_forward_,
    116119                   Xapian::ErrorHandler * errorhandler,
    117120                   StatsGatherer * gatherer_,
    118                    const Xapian::Weight *wtscheme);
     121                   const Xapian::Weight *wtscheme,
     122                   const Xapian::MatchCmp * match_cmp_);
    119123
    120124        void get_mset(Xapian::doccount first,
    121125                      Xapian::doccount maxitems,
  • xapian-core/common/remoteprotocol.h

     
    3030// 25: Support for delete_document and replace_document with unique term
    3131// 26: Tweak delete_document with unique term; delta encode rset and termpos
    3232// 27: Support for postlists (always passes the whole list across)
    33 #define XAPIAN_REMOTE_PROTOCOL_VERSION 27
     33// 28: MatchCmp serialisation
     34#define XAPIAN_REMOTE_PROTOCOL_VERSION 28
    3435
    3536/// Message types (client -> server).
    3637enum message_type {
  • xapian-core/common/remoteserver.h

     
    6868    /// Registered weighting schemes.
    6969    map<string, Xapian::Weight *> wtschemes;
    7070
     71    /// Registered match cmpfns.
     72    map<string, Xapian::MatchCmp *> match_cmps;
     73
    7174    /// Initialisation code needed by both ctors.
    7275    void initialise();
    7376
     
    186189    void register_weighting_scheme(const Xapian::Weight &wt) {
    187190        wtschemes[wt.name()] = wt.clone();
    188191    }
     192
     193    /// Register a user-defined match comparision class.
     194    void register_match_cmp(const Xapian::MatchCmp &match_cmp) {
     195        match_cmps[match_cmp.name()] = match_cmp.clone();
     196    }
    189197};
    190198
    191199#endif // XAPIAN_INCLUDED_REMOTESERVER_H
  • xapian-core/common/serialise.h

     
    2424#include <xapian/visibility.h>
    2525
    2626#include <string>
     27#include <xapian/database.h>
    2728
    2829// Forward class declarations:
    2930
     
    115116 *
    116117 *  @return     The unserialised Xapian::MSet object.
    117118 */
    118 Xapian::MSet unserialise_mset(const std::string &s);
     119Xapian::MSet unserialise_mset(const std::string &s,
     120                              Xapian::Internal::RefCntPtr<Xapian::Database::Internal> internal_db);
    119121
    120122/** Serialise a Xapian::RSet object.
    121123 *
  • xapian-core/api/omenquire.cc

     
    644644  : db(db_), query(), collapse_key(Xapian::BAD_VALUENO),
    645645    order(Enquire::ASCENDING), percent_cutoff(0), weight_cutoff(0),
    646646    sort_key(Xapian::BAD_VALUENO), sort_by(REL), sort_value_forward(true),
    647     errorhandler(errorhandler_), weight(0)
     647    sort_cmpfn(0), errorhandler(errorhandler_), weight(0)
    648648{
    649649}
    650650
    651651Enquire::Internal::~Internal()
    652652{
    653653    delete weight;
     654    delete sort_cmpfn;
    654655    weight = 0;
    655656}
    656657
     
    685686        ::MultiMatch match(db, query.internal.get(), qlen, RSet(), collapse_key,
    686687                       percent_cutoff, weight_cutoff,
    687688                       order, sort_key, sort_by, sort_value_forward,
    688                        errorhandler, new LocalStatsGatherer(), weight);
     689                       errorhandler, new LocalStatsGatherer(), weight, sort_cmpfn);
    689690        // Run query and put results into supplied Xapian::MSet object.
    690691        match.get_mset(first, maxitems, check_at_least, retval, mdecider);
    691692    } else {
    692693        ::MultiMatch match(db, query.internal.get(), qlen, *rset, collapse_key,
    693694                       percent_cutoff, weight_cutoff,
    694695                       order, sort_key, sort_by, sort_value_forward,
    695                        errorhandler, new LocalStatsGatherer(), weight);
     696                       errorhandler, new LocalStatsGatherer(), weight, sort_cmpfn);
    696697        // Run query and put results into supplied Xapian::MSet object.
    697698        match.get_mset(first, maxitems, check_at_least, retval, mdecider);
    698699    }
     
    909910{
    910911    DEBUGAPICALL(void, "Xapian::Enquire::set_weighting_scheme", "[Weight]");
    911912    delete internal->weight;
     913    internal->weight = NULL; // Set to NULL before cloning, to avoid double free if clone() throws an exception.
    912914    internal->weight = weight_.clone();
    913915}
    914916
     
    935937Enquire::set_sort_by_relevance()
    936938{
    937939    internal->sort_by = Internal::REL;
     940    delete internal->sort_cmpfn;
     941    internal->sort_cmpfn = NULL;
    938942}
    939943
    940944void
     
    943947    internal->sort_key = sort_key;
    944948    internal->sort_by = Internal::VAL;
    945949    internal->sort_value_forward = ascending;
     950    delete internal->sort_cmpfn;
     951    internal->sort_cmpfn = NULL;
    946952}
    947953
    948954void
     
    952958    internal->sort_key = sort_key;
    953959    internal->sort_by = Internal::VAL_REL;
    954960    internal->sort_value_forward = ascending;
     961    delete internal->sort_cmpfn;
     962    internal->sort_cmpfn = NULL;
    955963}
    956964
    957965void
     
    961969    internal->sort_key = sort_key;
    962970    internal->sort_by = Internal::REL_VAL;
    963971    internal->sort_value_forward = ascending;
     972    delete internal->sort_cmpfn;
     973    internal->sort_cmpfn = NULL;
    964974}
    965975
     976void
     977Enquire::set_sort_by_cmpfn(const MatchCmp &cmpfn_)
     978{
     979    DEBUGAPICALL(void, "Xapian::Enquire::set_sort_by_cmpfn", "[cmpfn:" << cmpfn_.name() << "(" << cmpfn_.serialise() << ")]");
     980    delete internal->sort_cmpfn;
     981    internal->sort_by = Internal::USER;
     982    internal->sort_cmpfn = NULL; // Set to NULL before cloning, to avoid double free if clone() throws an exception.
     983    internal->sort_cmpfn = cmpfn_.clone();
     984}
     985
    966986MSet
    967987Enquire::get_mset(Xapian::doccount first, Xapian::doccount maxitems,
    968988                  Xapian::doccount check_at_least, const RSet *rset,
  • xapian-core/backends/remote/remote-database.cc

     
    409409                         bool sort_value_forward,
    410410                         int percent_cutoff, Xapian::weight weight_cutoff,
    411411                         const Xapian::Weight *wtscheme,
     412                         const Xapian::MatchCmp *sort_cmpfn,
    412413                         const Xapian::RSet &omrset)
    413414{
    414415    string tmp = query->serialise();
     
    425426    message += char(percent_cutoff);
    426427    message += serialise_double(weight_cutoff);
    427428
     429    // Serialise the weight scheme
    428430    tmp = wtscheme->name();
    429431    message += encode_length(tmp.size());
    430432    message += tmp;
    431 
    432433    tmp = wtscheme->serialise();
    433434    message += encode_length(tmp.size());
    434435    message += tmp;
    435436
     437    // Serialise the match cmp object
     438    if (sort_cmpfn == NULL) {
     439        message += encode_length(0);
     440    } else {
     441        tmp = sort_cmpfn->name();
     442        message += encode_length(tmp.size());
     443        message += tmp;
     444        tmp = sort_cmpfn->serialise();
     445        message += encode_length(tmp.size());
     446        message += tmp;
     447    }
     448
    436449    message += serialise_rset(omrset);
    437450
    438451    send_message(MSG_QUERY, message);
     
    466479{
    467480    string message;
    468481    get_message(message, REPLY_RESULTS);
    469     mset = unserialise_mset(message);
     482    mset = unserialise_mset(message, this);
    470483}
    471484
    472485void
  • xapian-bindings/csharp/Makefile.am

     
    2323        ExpandDecider.cs \
    2424        Flint.cs \
    2525        InMemory.cs \
     26        MatchCmp.cs \
     27        MatchItem.cs \
    2628        MatchDecider.cs \
    2729        MSet.cs \
    2830        MSetIterator.cs \
     
    3537        RSet.cs \
    3638        SWIGTYPE_p_std__vectorTstd__string_t.cs \
    3739        SWIGTYPE_p_std__vectorTXapian__Query_t.cs \
     40        SWIGTYPE_p_Xapian__Internal__MSetItem.cs \
    3841        SimpleStopper.cs \
    3942        Stem.cs \
    4043        Stopper.cs \
  • xapian-bindings/xapian.i

     
    156156int xapian_revision();
    157157
    158158class Weight;
     159class MatchCmp;
    159160class Stopper;
    160161
    161162// from xapian/positioniterator.h
     
    482483                                          bool ascending = true);
    483484    void set_sort_by_relevance_then_value(Xapian::valueno sort_key,
    484485                                          bool ascending = true);
     486    void set_sort_by_cmpfn(const MatchCmp& cmpfn);
    485487
    486488#ifdef XAPIAN_SWIG_DIRECTORS
    487489    MSet get_mset(doccount first,
     
    635637        bool get_sumpart_needs_doclength() const;
    636638};
    637639
     640class MatchItem {
     641    public:
     642        MatchItem(const Xapian::Internal::MSetItem & item_);
     643        Xapian::weight get_wt() const;
     644        Xapian::docid get_docid() const;
     645        Xapian::Document get_document() const;
     646};
     647
     648class MatchCmp {
     649/* SWIG doesn't handle this:
     650    private:
     651        virtual MatchCmp * clone() const = 0; */
     652    public:
     653        virtual ~MatchCmp();
     654
     655        virtual std::string name() const = 0;
     656        virtual std::string serialise() const = 0;
     657        virtual MatchCmp * unserialise(const std::string &s) const = 0;
     658
     659        virtual int cmp(const MatchItem & a,
     660                        const MatchItem & b) const = 0;
     661};
     662
     663%warnfilter(842) IntegerMatchCmp::unserialise;
     664class IntegerMatchCmp : public MatchCmp {
     665    public:
     666        IntegerMatchCmp * clone() const;
     667        IntegerMatchCmp(Xapian::valueno sort_key_,
     668                        bool ascending = true);
     669        IntegerMatchCmp();
     670        ~IntegerMatchCmp();
     671
     672        std::string name() const;
     673        std::string serialise() const;
     674        IntegerMatchCmp * unserialise(const std::string &s) const;
     675
     676        int cmp(const MatchItem & a,
     677                const MatchItem & b) const;
     678
     679        static std::string int_to_value(int num);
     680        static int value_to_int(const std::string &s);
     681};
     682
     683%warnfilter(842) DoubleMatchCmp::unserialise;
     684class DoubleMatchCmp : public MatchCmp {
     685    public:
     686        DoubleMatchCmp * clone() const;
     687        DoubleMatchCmp(Xapian::valueno sort_key_,
     688                        bool ascending = true);
     689        DoubleMatchCmp();
     690        ~DoubleMatchCmp();
     691
     692        std::string name() const;
     693        std::string serialise() const;
     694        DoubleMatchCmp * unserialise(const std::string &s) const;
     695
     696        int cmp(const MatchItem & a,
     697                const MatchItem & b) const;
     698
     699        static std::string double_to_value(double num);
     700        static double value_to_double(const std::string &s);
     701};
     702
     703
    638704// xapian/database.h
    639705
    640706class Database {