Ticket #186: ref-counted-subclassables.patch

File ref-counted-subclassables.patch, 10.8 KB (added by Olly Betts, 11 years ago)

Proposed patch (updated)

  • xapian-bindings/perl/perl.i

    diff --git a/xapian-bindings/perl/perl.i b/xapian-bindings/perl/perl.i
    index 1ae61d3..317b515 100644
    a b sub set_stopper {  
    343343}
    344344%}
    345345
    346 %feature("shadow") Xapian::QueryParser::add_valuerangeprocessor
    347 %{
    348 sub add_valuerangeprocessor {
    349     my ($self, $vrproc) = @_;
    350     push @{$self{_vrproc}}, $vrproc;
    351     Search::Xapianc::QueryParser_add_valuerangeprocessor( @_ );
    352 }
    353 %}
    354 
    355346/* Xapian::SimpleStopper */
    356347%feature("shadow") Xapian::SimpleStopper::SimpleStopper
    357348%{
  • xapian-bindings/python/extra.i

    diff --git a/xapian-bindings/python/extra.i b/xapian-bindings/python/extra.i
    index 0d24f0b..f819924 100644
    a b _enquire_get_query.__doc__ = __enquire_get_query_orig.__doc__  
    728728Enquire.get_query = _enquire_get_query
    729729del _enquire_get_query
    730730
    731 # When we set a ValueRangeProcessor into the QueryParser, keep a python
    732 # reference so it won't be deleted. This hack can probably be removed once
    733 # xapian bug #186 is fixed.
    734 __queryparser_add_valuerangeprocessor_orig = QueryParser.add_valuerangeprocessor
    735 def _queryparser_add_valuerangeprocessor(self, vrproc):
    736     if not hasattr(self, '_vrps'):
    737         self._vrps = []
    738     self._vrps.append(vrproc)
    739     return __queryparser_add_valuerangeprocessor_orig(self, vrproc)
    740 _queryparser_add_valuerangeprocessor.__doc__ = __queryparser_add_valuerangeprocessor_orig.__doc__
    741 QueryParser.add_valuerangeprocessor = _queryparser_add_valuerangeprocessor
    742 del _queryparser_add_valuerangeprocessor
    743 
    744731# When we set a FieldProcessor into the QueryParser, keep a python
    745732# reference so it won't be deleted. This hack can probably be removed once
    746733# xapian bug #186 is fixed.
  • xapian-bindings/xapian-headers.i

    diff --git a/xapian-bindings/xapian-headers.i b/xapian-bindings/xapian-headers.i
    index 85ec281..9e09d68 100644
    a b SUBCLASSABLE(Xapian, KeyMaker)  
    324324SUBCLASSABLE(Xapian, FieldProcessor)
    325325SUBCLASSABLE(Xapian, Stopper)
    326326SUBCLASSABLE(Xapian, ValueRangeProcessor)
     327%warnfilter(SWIGWARN_TYPE_UNDEFINED_CLASS) Xapian::ValueRangeProcessor;
     328%feature("ref") Xapian::ValueRangeProcessor "$this->ref();"
     329%feature("unref") Xapian::ValueRangeProcessor "$this->unref();"
    327330STANDARD_IGNORES(Xapian, QueryParser)
    328331%ignore Xapian::QueryParser::QueryParser(const QueryParser &);
    329332%include <xapian/queryparser.h>
  • xapian-core/include/xapian/intrusive_ptr.h

    diff --git a/xapian-core/include/xapian/intrusive_ptr.h b/xapian-core/include/xapian/intrusive_ptr.h
    index 4290782..4376897 100644
    a b  
    55//  Based on Boost's intrusive_ptr.hpp
    66//
    77//  Copyright (c) 2001, 2002 Peter Dimov
    8 //  Copyright (c) 2011 Olly Betts
     8//  Copyright (c) 2011, 2013 Olly Betts
    99//
    1010// Distributed under the Boost Software License, Version 1.0.
    1111//
    template<class T, class U> inline bool operator!=(T * a, intrusive_ptr<U> const  
    175175    return a != b.get();
    176176}
    177177
     178/// Base class for objects managed by opt_intrusive_ptr.
     179class opt_intrusive_base : public intrusive_base {
     180  public:
     181    opt_intrusive_base(const opt_intrusive_base&) : intrusive_base() { }
     182
     183    opt_intrusive_base& operator=(const opt_intrusive_base&) {
     184        // Don't touch _refs.
     185        return *this;
     186    }
     187
     188    /** Construct object which is initially not reference counted.
     189     *
     190     *  The reference counting starts if release_() is called.
     191     */
     192    opt_intrusive_base() : intrusive_base() { }
     193
     194    /* Subclasses of opt_intrusive_base may be deleted by calling delete on a
     195     * pointer to intrusive_base*.
     196     */
     197    virtual ~opt_intrusive_base() { }
     198
     199    /** Start reference counting.
     200     *
     201     *  The object is constructed with _refs set to 0, meaning it isn't being
     202     *  reference counted.
     203     *
     204     *  Calling release() sets _refs to 1 if it is 0, and from then
     205     *  opt_intrusive_ptr will increment and decrement _refs.  If it is
     206     *  decremented to 1, the object is deleted.
     207     */
     208    void release() const {
     209        if (_refs == 0)
     210            _refs = 1;
     211    }
     212
     213    void ref() const {
     214        if (_refs == 0)
     215            _refs = 2;
     216        else
     217            ++_refs;
     218    }
     219
     220    void unref() const {
     221        if (--_refs == 1)
     222            delete this;
     223    }
     224};
     225
     226//
     227//  opt_intrusive_ptr
     228//
     229
     230/// A smart pointer that uses intrusive reference counting.
     231template<class T> class opt_intrusive_ptr
     232{
     233private:
     234
     235    typedef opt_intrusive_ptr this_type;
     236
     237public:
     238
     239    opt_intrusive_ptr(): px( 0 )
     240    {
     241    }
     242
     243    opt_intrusive_ptr( T * p): px( p )
     244    {
     245        if( px != 0 && px->_refs ) ++px->_refs;
     246    }
     247
     248    template<class U>
     249    opt_intrusive_ptr( opt_intrusive_ptr<U> const & rhs )
     250    : px( rhs.get() )
     251    {
     252        if( px != 0 && px->_refs ) ++px->_refs;
     253    }
     254
     255    opt_intrusive_ptr(opt_intrusive_ptr const & rhs): px( rhs.px )
     256    {
     257        if( px != 0 && px->_refs ) ++px->_refs;
     258    }
     259
     260    ~opt_intrusive_ptr()
     261    {
     262        if( px != 0 && px->_refs && --px->_refs == 1 ) delete px;
     263    }
     264
     265    opt_intrusive_ptr & operator=(opt_intrusive_ptr const & rhs)
     266    {
     267        this_type(rhs).swap(*this);
     268        return *this;
     269    }
     270
     271    opt_intrusive_ptr & operator=(T * rhs)
     272    {
     273        this_type(rhs).swap(*this);
     274        return *this;
     275    }
     276
     277    T * get() const
     278    {
     279        return px;
     280    }
     281
     282    T & operator*() const
     283    {
     284        return *px;
     285    }
     286
     287    T * operator->() const
     288    {
     289        return px;
     290    }
     291
     292    void swap(opt_intrusive_ptr & rhs)
     293    {
     294        T * tmp = px;
     295        px = rhs.px;
     296        rhs.px = tmp;
     297    }
     298
     299private:
     300
     301    T * px;
     302};
     303
     304template<class T, class U> inline bool operator==(opt_intrusive_ptr<T> const & a, opt_intrusive_ptr<U> const & b)
     305{
     306    return a.get() == b.get();
     307}
     308
     309template<class T, class U> inline bool operator!=(opt_intrusive_ptr<T> const & a, opt_intrusive_ptr<U> const & b)
     310{
     311    return a.get() != b.get();
     312}
     313
     314template<class T, class U> inline bool operator==(opt_intrusive_ptr<T> const & a, U * b)
     315{
     316    return a.get() == b;
     317}
     318
     319template<class T, class U> inline bool operator!=(opt_intrusive_ptr<T> const & a, U * b)
     320{
     321    return a.get() != b;
     322}
     323
     324template<class T, class U> inline bool operator==(T * a, opt_intrusive_ptr<U> const & b)
     325{
     326    return a == b.get();
     327}
     328
     329template<class T, class U> inline bool operator!=(T * a, opt_intrusive_ptr<U> const & b)
     330{
     331    return a != b.get();
     332}
     333
    178334}
    179335}
    180336
  • xapian-core/include/xapian/queryparser.h

    diff --git a/xapian-core/include/xapian/queryparser.h b/xapian-core/include/xapian/queryparser.h
    index 84b5c43..b3b169b 100644
    a b  
    11/** @file queryparser.h
    22 * @brief parsing a user query string to build a Xapian::Query object
    33 */
    4 /* Copyright (C) 2005,2006,2007,2008,2009,2010,2011,2012 Olly Betts
     4/* Copyright (C) 2005,2006,2007,2008,2009,2010,2011,2012,2013 Olly Betts
    55 * Copyright (C) 2010 Adam Sjøgren
    66 *
    77 * This program is free software; you can redistribute it and/or
    class XAPIAN_VISIBILITY_DEFAULT SimpleStopper : public Stopper {  
    8585};
    8686
    8787/// Base class for value range processors.
    88 struct XAPIAN_VISIBILITY_DEFAULT ValueRangeProcessor {
     88struct XAPIAN_VISIBILITY_DEFAULT ValueRangeProcessor
     89    : public Xapian::Internal::opt_intrusive_base {
    8990    /// Destructor.
    9091    virtual ~ValueRangeProcessor();
    9192
  • xapian-core/queryparser/queryparser.lemony

    diff --git a/xapian-core/queryparser/queryparser.lemony b/xapian-core/queryparser/queryparser.lemony
    index 8fd3b8c..c02add3 100644
    a b  
    11%include {
    22/* queryparser.lemony: build a Xapian::Query object from a user query string.
    33 *
    4  * Copyright (C) 2004,2005,2006,2007,2008,2009,2010,2011,2012 Olly Betts
     4 * Copyright (C) 2004,2005,2006,2007,2008,2009,2010,2011,2012,2013 Olly Betts
    55 * Copyright (C) 2007,2008,2009 Lemur Consulting Ltd
    66 * Copyright (C) 2010 Adam Sjøgren
    77 *
    class State {  
    252252    }
    253253
    254254    Term * value_range(const string &a, const string &b) {
    255         list<ValueRangeProcessor *>::const_iterator i;
     255        list<Xapian::Internal::opt_intrusive_ptr<Xapian::ValueRangeProcessor> >::const_iterator i;
    256256        for (i = qpi->valrangeprocs.begin(); i != qpi->valrangeprocs.end(); ++i) {
    257257            string start = a;
    258258            string end = b;
  • xapian-core/queryparser/queryparser_internal.h

    diff --git a/xapian-core/queryparser/queryparser_internal.h b/xapian-core/queryparser/queryparser_internal.h
    index 11da6fc..7e02532 100644
    a b  
    11/** @file queryparser_internal.h
    22 * @brief The non-lemon-generated parts of the QueryParser class.
    33 */
    4 /* Copyright (C) 2005,2006,2007,2010,2011,2012 Olly Betts
     4/* Copyright (C) 2005,2006,2007,2010,2011,2012,2013 Olly Betts
    55 * Copyright (C) 2010 Adam Sjøgren
    66 *
    77 * This program is free software; you can redistribute it and/or
    class QueryParser::Internal : public Xapian::Internal::intrusive_base {  
    8282    // "foobar" -> "XFOO". FIXME: it does more than this now!
    8383    map<string, FieldInfo> field_map;
    8484
    85     list<ValueRangeProcessor *> valrangeprocs;
     85    list<Xapian::Internal::opt_intrusive_ptr<ValueRangeProcessor> > valrangeprocs;
    8686
    8787    string corrected_query;
    8888
  • xapian-core/tests/api_none.cc

    diff --git a/xapian-core/tests/api_none.cc b/xapian-core/tests/api_none.cc
    index 2f4340f..f6e3e7c 100644
    a b  
    22 * @brief tests which don't need a backend
    33 */
    44/* Copyright (C) 2009 Richard Boulton
    5  * Copyright (C) 2009,2010,2011 Olly Betts
     5 * Copyright (C) 2009,2010,2011,2013 Olly Betts
    66 *
    77 * This program is free software; you can redistribute it and/or
    88 * modify it under the terms of the GNU General Public License as
    DEFINE_TESTCASE(combinewqfnomore1, !backend) {  
    142142    TEST_EQUAL(q.get_description(), "Query((beer@1 OR beer@1))");
    143143    return true;
    144144}
     145
     146struct TestValueRangeProcessor : public Xapian::ValueRangeProcessor {
     147    bool & destroyed;
     148
     149    TestValueRangeProcessor(bool & destroyed_) : destroyed(destroyed_) {
     150        destroyed = false;
     151    }
     152
     153    ~TestValueRangeProcessor() {
     154        destroyed = true;
     155    }
     156
     157    Xapian::valueno operator()(std::string &, std::string &) {
     158        return 42;
     159    }
     160};
     161
     162/// Check reference counting of user-subclassable classes.
     163DEFINE_TESTCASE(subclassablerefcount1, !backend) {
     164    bool gone_auto, gone;
     165    {
     166        TestValueRangeProcessor vrp_auto(gone_auto);
     167        TEST(!gone_auto);
     168        {
     169            Xapian::QueryParser qp1;
     170            {
     171                Xapian::QueryParser qp2;
     172                Xapian::ValueRangeProcessor * vrp;
     173                vrp = new TestValueRangeProcessor(gone);
     174                TEST(!gone);
     175                vrp->release();
     176                qp1.add_valuerangeprocessor(vrp);
     177                TEST(!gone);
     178                qp2.add_valuerangeprocessor(vrp);
     179                TEST(!gone);
     180                qp2.add_valuerangeprocessor(&vrp_auto);
     181                TEST(!gone);
     182                TEST(!gone_auto);
     183            }
     184            TEST(!gone);
     185        }
     186        TEST(gone);
     187        TEST(!gone_auto);
     188    }
     189    TEST(gone_auto);
     190
     191    return true;
     192}