LCOV - code coverage report
Current view: top level - api - registry.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core eba1a2e3082b Lines: 161 172 93.6 %
Date: 2019-06-13 13:35:36 Functions: 25 27 92.6 %
Branches: 130 306 42.5 %

           Branch data     Line data    Source code
       1                 :            : /** @file registry.cc
       2                 :            :  * @brief Class for looking up user subclasses during unserialisation.
       3                 :            :  */
       4                 :            : /* Copyright (C) 2006,2007,2008,2009,2010,2016 Olly Betts
       5                 :            :  * Copyright (C) 2006,2007,2009 Lemur Consulting Ltd
       6                 :            :  *
       7                 :            :  * This program is free software; you can redistribute it and/or
       8                 :            :  * modify it under the terms of the GNU General Public License as
       9                 :            :  * published by the Free Software Foundation; either version 2 of the
      10                 :            :  * License, or (at your option) any later version.
      11                 :            :  *
      12                 :            :  * This program is distributed in the hope that it will be useful,
      13                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15                 :            :  * GNU General Public License for more details.
      16                 :            :  *
      17                 :            :  * You should have received a copy of the GNU General Public License
      18                 :            :  * along with this program; if not, write to the Free Software
      19                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
      20                 :            :  */
      21                 :            : 
      22                 :            : #include <config.h>
      23                 :            : 
      24                 :            : #include "xapian/registry.h"
      25                 :            : 
      26                 :            : #include "xapian/error.h"
      27                 :            : #include "xapian/geospatial.h"
      28                 :            : #include "xapian/intrusive_ptr.h"
      29                 :            : #include "xapian/matchspy.h"
      30                 :            : #include "xapian/postingsource.h"
      31                 :            : #include "xapian/weight.h"
      32                 :            : 
      33                 :            : #include "debuglog.h"
      34                 :            : #include "stringutils.h"
      35                 :            : 
      36                 :            : #include <algorithm>
      37                 :            : #include <map>
      38                 :            : #include <string>
      39                 :            : 
      40                 :            : using namespace std;
      41                 :            : 
      42                 :            : class Xapian::Registry::Internal : public Xapian::Internal::intrusive_base {
      43                 :            :     friend class Xapian::Registry;
      44                 :            : 
      45                 :            :     /// Registered weighting schemes.
      46                 :            :     std::map<std::string, Xapian::Weight *> wtschemes;
      47                 :            : 
      48                 :            :     /// Registered weighting schemes by their short names. E.g. "bm25".
      49                 :            :     std::map<std::string, Xapian::Weight *> wtschemes_short;
      50                 :            : 
      51                 :            :     /// Registered external posting sources.
      52                 :            :     std::map<std::string, Xapian::PostingSource *> postingsources;
      53                 :            : 
      54                 :            :     /// Registered match spies.
      55                 :            :     std::map<std::string, Xapian::MatchSpy *> matchspies;
      56                 :            : 
      57                 :            :     /// Registered lat-long metrics.
      58                 :            :     std::map<std::string, Xapian::LatLongMetric *> lat_long_metrics;
      59                 :            : 
      60                 :            :     /// Add the standard subclasses provided in the API.
      61                 :            :     void add_defaults();
      62                 :            : 
      63                 :            :     /// Clear all registered weighting schemes.
      64                 :            :     void clear_weighting_schemes();
      65                 :            : 
      66                 :            :     /// Clear all registered posting sources.
      67                 :            :     void clear_posting_sources();
      68                 :            : 
      69                 :            :     /// Clear all registered match spies.
      70                 :            :     void clear_match_spies();
      71                 :            : 
      72                 :            :     /// Clear all registered lat-long metrics.
      73                 :            :     void clear_lat_long_metrics();
      74                 :            : 
      75                 :            :   public:
      76                 :            :     Internal();
      77                 :            :     ~Internal();
      78                 :            : };
      79                 :            : 
      80                 :            : template<class T>
      81                 :            : static inline void
      82                 :          8 : register_object(map<string, T*> & registry, const T & obj)
      83                 :            : {
      84 [ #  # ][ +  - ]:          8 :     string name = obj.name();
                 [ +  - ]
      85 [ #  # ][ -  + ]:          8 :     if (rare(name.empty())) {
                 [ -  + ]
      86 [ #  # ][ #  # ]:          0 :         throw Xapian::InvalidOperationError("Unable to register object - name() method returned empty string");
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      87                 :            :     }
      88                 :            : 
      89 [ #  # ][ +  - ]:          8 :     pair<typename map<string, T *>::iterator, bool> r;
                 [ +  - ]
      90 [ #  # ][ #  # ]:          8 :     r = registry.insert(make_pair(name, static_cast<T*>(NULL)));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
      91   [ #  #  +  +  :          8 :     if (!r.second) {
                   +  + ]
      92                 :            :         // Existing element with this key, so replace the pointer with NULL
      93                 :            :         // and delete the existing pointer.
      94                 :            :         //
      95                 :            :         // If the delete throws, this will leave a NULL entry in the map, but
      96                 :            :         // that won't affect behaviour as we return NULL for "not found"
      97                 :            :         // anyway.  The memory used will be leaked if the dtor throws, but
      98                 :            :         // throwing exceptions from the dtor is bad form, so that's not a big
      99                 :            :         // problem.
     100                 :          4 :         T * p = NULL;
     101                 :          4 :         swap(p, r.first->second);
     102 [ #  # ][ +  - ]:          4 :         delete p;
                 [ +  - ]
     103                 :            :     }
     104                 :            : 
     105 [ #  # ][ +  + ]:          8 :     T * clone = obj.clone();
                 [ +  + ]
     106 [ #  # ][ -  + ]:          6 :     if (rare(!clone)) {
                 [ -  + ]
     107 [ #  # ][ #  # ]:          0 :         throw Xapian::InvalidOperationError("Unable to register object - clone() method returned NULL");
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     108                 :            :     }
     109                 :            : 
     110                 :          8 :     r.first->second = clone;
     111                 :          6 : }
     112                 :            : 
     113                 :            : template<class T>
     114                 :            : static inline void
     115                 :          5 : register_object(map<string, T*> & registry1, map<string, T*> & registry2,
     116                 :            :                 const T & obj)
     117                 :            : {
     118         [ +  - ]:          5 :     string name = obj.name();
     119         [ -  + ]:          5 :     if (rare(name.empty())) {
     120 [ #  # ][ #  # ]:          0 :         throw Xapian::InvalidOperationError("Unable to register object - name() method returned empty string");
                 [ #  # ]
     121                 :            :     }
     122                 :            : 
     123         [ +  - ]:          5 :     pair<typename map<string, T *>::iterator, bool> r1;
     124 [ +  - ][ +  - ]:          5 :     r1 = registry1.insert(make_pair(name, static_cast<T*>(NULL)));
     125                 :            : 
     126         [ +  - ]:          5 :     pair<typename map<string, T *>::iterator, bool> r2;
     127         [ +  - ]:         10 :     string short_name = obj.short_name();
     128         [ +  - ]:          5 :     if (!short_name.empty()) {
     129 [ +  - ][ +  - ]:          5 :         r2 = registry2.insert(make_pair(short_name, static_cast<T*>(NULL)));
     130 [ +  - ][ +  + ]:          5 :         if (r1.second != r2.second || (!r1.second && r2.first->second != r1.first->second)) {
         [ -  + ][ -  + ]
     131 [ #  # ][ #  # ]:          0 :             throw Xapian::InvalidOperationError("Unable to register object - weighting scheme with the same name but a different short name already registered");
                 [ #  # ]
     132                 :            :         }
     133                 :            :     }
     134                 :            : 
     135         [ +  + ]:          5 :     if (!r1.second) {
     136                 :            :         // Existing element with this key, so replace the pointer with NULL
     137                 :            :         // and delete the existing pointer.
     138                 :            :         //
     139                 :            :         // If the delete throws, this will leave a NULL entry in the map, but
     140                 :            :         // that won't affect behaviour as we return NULL for "not found"
     141                 :            :         // anyway.  The memory used will be leaked if the dtor throws, but
     142                 :            :         // throwing exceptions from the dtor is bad form, so that's not a big
     143                 :            :         // problem.
     144                 :          4 :         T * p = NULL;
     145                 :          4 :         swap(p, r1.first->second);
     146         [ +  - ]:          4 :         delete p;
     147                 :            :     }
     148                 :            : 
     149         [ +  + ]:          5 :     T * clone = obj.clone();
     150         [ -  + ]:          4 :     if (rare(!clone)) {
     151 [ #  # ][ #  # ]:          0 :         throw Xapian::InvalidOperationError("Unable to register object - clone() method returned NULL");
                 [ #  # ]
     152                 :            :     }
     153                 :            : 
     154                 :          4 :     r1.first->second = clone;
     155                 :            : 
     156         [ +  - ]:          4 :     if (!short_name.empty()) {
     157                 :          4 :         r2.first->second = clone;
     158                 :          5 :     }
     159                 :          4 : }
     160                 :            : 
     161                 :            : template<class T>
     162                 :            : static inline const T *
     163                 :      10465 : lookup_object(map<string, T*> registry, const string & name)
     164                 :            : {
     165 [ +  - ][ +  - ]:      10465 :     typename map<string, T*>::const_iterator i = registry.find(name);
         [ +  - ][ +  - ]
     166   [ -  +  -  +  :      10465 :     if (i == registry.end()) {
             +  +  -  + ]
     167                 :          2 :         return NULL;
     168                 :            :     }
     169                 :      10465 :     return i->second;
     170                 :            : }
     171                 :            : 
     172                 :            : namespace Xapian {
     173                 :            : 
     174 [ +  - ][ +  - ]:       2894 : Registry::Internal::Internal()
         [ +  - ][ +  - ]
     175                 :            : {
     176         [ +  - ]:       1447 :     add_defaults();
     177                 :       1447 : }
     178                 :            : 
     179                 :       2894 : Registry::Internal::~Internal()
     180                 :            : {
     181                 :       1447 :     clear_weighting_schemes();
     182                 :       1447 :     clear_posting_sources();
     183                 :       1447 :     clear_match_spies();
     184                 :       1447 :     clear_lat_long_metrics();
     185                 :       1447 : }
     186                 :            : 
     187                 :            : void
     188                 :       1447 : Registry::Internal::add_defaults()
     189                 :            : {
     190                 :            :     Xapian::Weight * weighting_scheme;
     191                 :       1447 :     weighting_scheme = new Xapian::BB2Weight;
     192         [ +  - ]:       1447 :     wtschemes[weighting_scheme->name()] = weighting_scheme;
     193         [ +  - ]:       1447 :     wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
     194                 :       1447 :     weighting_scheme = new Xapian::BM25Weight;
     195         [ +  - ]:       1447 :     wtschemes[weighting_scheme->name()] = weighting_scheme;
     196         [ +  - ]:       1447 :     wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
     197                 :       1447 :     weighting_scheme = new Xapian::BM25PlusWeight;
     198         [ +  - ]:       1447 :     wtschemes[weighting_scheme->name()] = weighting_scheme;
     199         [ +  - ]:       1447 :     wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
     200                 :       1447 :     weighting_scheme = new Xapian::BoolWeight;
     201         [ +  - ]:       1447 :     wtschemes[weighting_scheme->name()] = weighting_scheme;
     202         [ +  - ]:       1447 :     wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
     203                 :       1447 :     weighting_scheme = new Xapian::CoordWeight;
     204         [ +  - ]:       1447 :     wtschemes[weighting_scheme->name()] = weighting_scheme;
     205         [ +  - ]:       1447 :     wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
     206                 :       1447 :     weighting_scheme = new Xapian::TradWeight;
     207         [ +  - ]:       1447 :     wtschemes[weighting_scheme->name()] = weighting_scheme;
     208         [ +  - ]:       1447 :     wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
     209         [ +  - ]:       1447 :     weighting_scheme = new Xapian::TfIdfWeight;
     210         [ +  - ]:       1447 :     wtschemes[weighting_scheme->name()] = weighting_scheme;
     211         [ +  - ]:       1447 :     wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
     212                 :       1447 :     weighting_scheme = new Xapian::InL2Weight;
     213         [ +  - ]:       1447 :     wtschemes[weighting_scheme->name()] = weighting_scheme;
     214         [ +  - ]:       1447 :     wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
     215                 :       1447 :     weighting_scheme = new Xapian::IfB2Weight;
     216         [ +  - ]:       1447 :     wtschemes[weighting_scheme->name()] = weighting_scheme;
     217         [ +  - ]:       1447 :     wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
     218                 :       1447 :     weighting_scheme = new Xapian::IneB2Weight;
     219         [ +  - ]:       1447 :     wtschemes[weighting_scheme->name()] = weighting_scheme;
     220         [ +  - ]:       1447 :     wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
     221                 :       1447 :     weighting_scheme = new Xapian::DLHWeight;
     222         [ +  - ]:       1447 :     wtschemes[weighting_scheme->name()] = weighting_scheme;
     223         [ +  - ]:       1447 :     wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
     224                 :       1447 :     weighting_scheme = new Xapian::PL2PlusWeight;
     225         [ +  - ]:       1447 :     wtschemes[weighting_scheme->name()] = weighting_scheme;
     226         [ +  - ]:       1447 :     wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
     227                 :       1447 :     weighting_scheme = new Xapian::PL2Weight;
     228         [ +  - ]:       1447 :     wtschemes[weighting_scheme->name()] = weighting_scheme;
     229         [ +  - ]:       1447 :     wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
     230                 :       1447 :     weighting_scheme = new Xapian::DPHWeight;
     231         [ +  - ]:       1447 :     wtschemes[weighting_scheme->name()] = weighting_scheme;
     232         [ +  - ]:       1447 :     wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
     233                 :       1447 :     weighting_scheme = new Xapian::LMWeight;
     234         [ +  - ]:       1447 :     wtschemes[weighting_scheme->name()] = weighting_scheme;
     235         [ +  - ]:       1447 :     wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
     236                 :       1447 :     weighting_scheme = new Xapian::DiceCoeffWeight;
     237         [ +  - ]:       1447 :     wtschemes[weighting_scheme->name()] = weighting_scheme;
     238         [ +  - ]:       1447 :     wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
     239                 :            : 
     240                 :            :     Xapian::PostingSource * source;
     241         [ +  - ]:       1447 :     source = new Xapian::ValueWeightPostingSource(0);
     242         [ +  - ]:       1447 :     postingsources[source->name()] = source;
     243         [ +  - ]:       1447 :     source = new Xapian::DecreasingValueWeightPostingSource(0);
     244         [ +  - ]:       1447 :     postingsources[source->name()] = source;
     245         [ +  - ]:       1447 :     source = new Xapian::ValueMapPostingSource(0);
     246         [ +  - ]:       1447 :     postingsources[source->name()] = source;
     247         [ +  - ]:       1447 :     source = new Xapian::FixedWeightPostingSource(0.0);
     248         [ +  - ]:       1447 :     postingsources[source->name()] = source;
     249                 :            :     source = new Xapian::LatLongDistancePostingSource(0,
     250                 :            :         Xapian::LatLongCoords(),
     251 [ +  - ][ +  - ]:       1447 :         Xapian::GreatCircleMetric());
                 [ +  - ]
     252         [ +  - ]:       1447 :     postingsources[source->name()] = source;
     253                 :            : 
     254                 :            :     Xapian::MatchSpy * spy;
     255         [ +  - ]:       1447 :     spy = new Xapian::ValueCountMatchSpy();
     256         [ +  - ]:       1447 :     matchspies[spy->name()] = spy;
     257                 :            : 
     258                 :            :     Xapian::LatLongMetric * metric;
     259         [ +  - ]:       1447 :     metric = new Xapian::GreatCircleMetric();
     260         [ +  - ]:       1447 :     lat_long_metrics[metric->name()] = metric;
     261                 :       1447 : }
     262                 :            : 
     263                 :            : void
     264                 :       1447 : Registry::Internal::clear_weighting_schemes()
     265                 :            : {
     266                 :       1447 :     map<string, Xapian::Weight*>::const_iterator i;
     267         [ +  + ]:      24600 :     for (i = wtschemes.begin(); i != wtschemes.end(); ++i) {
     268         [ +  + ]:      23153 :         delete i->second;
     269                 :            :     }
     270                 :       1447 : }
     271                 :            : 
     272                 :            : void
     273                 :       1447 : Registry::Internal::clear_posting_sources()
     274                 :            : {
     275                 :       1447 :     map<string, Xapian::PostingSource *>::const_iterator i;
     276         [ +  + ]:       8685 :     for (i = postingsources.begin(); i != postingsources.end(); ++i) {
     277         [ +  + ]:       7238 :         delete i->second;
     278                 :            :     }
     279                 :       1447 : }
     280                 :            : 
     281                 :            : void
     282                 :       1447 : Registry::Internal::clear_match_spies()
     283                 :            : {
     284                 :       1447 :     map<string, Xapian::MatchSpy *>::const_iterator i;
     285         [ +  + ]:       2895 :     for (i = matchspies.begin(); i != matchspies.end(); ++i) {
     286         [ +  + ]:       1448 :         delete i->second;
     287                 :            :     }
     288                 :       1447 : }
     289                 :            : 
     290                 :            : void
     291                 :       1447 : Registry::Internal::clear_lat_long_metrics()
     292                 :            : {
     293                 :       1447 :     map<string, Xapian::LatLongMetric *>::const_iterator i;
     294         [ +  + ]:       2894 :     for (i = lat_long_metrics.begin(); i != lat_long_metrics.end(); ++i) {
     295         [ +  - ]:       1447 :         delete i->second;
     296                 :            :     }
     297                 :       1447 : }
     298                 :            : 
     299                 :          1 : Registry::Registry(const Registry & other)
     300                 :          1 :         : internal(other.internal)
     301                 :            : {
     302                 :            :     LOGCALL_CTOR(API, "Registry", other);
     303                 :          1 : }
     304                 :            : 
     305                 :            : Registry &
     306                 :        711 : Registry::operator=(const Registry & other)
     307                 :            : {
     308                 :            :     LOGCALL(API, Xapian::Registry &, "Xapian::Registry::operator=", other);
     309                 :        711 :     internal = other.internal;
     310                 :        711 :     RETURN(*this);
     311                 :            : }
     312                 :            : 
     313                 :            : Registry::Registry(Registry &&) = default;
     314                 :            : 
     315                 :            : Registry &
     316                 :            : Registry::operator=(Registry &&) = default;
     317                 :            : 
     318                 :       1447 : Registry::Registry()
     319         [ +  - ]:       1447 :         : internal(new Registry::Internal())
     320                 :            : {
     321                 :            :     LOGCALL_CTOR(API, "Registry", NO_ARGS);
     322                 :       1447 : }
     323                 :            : 
     324                 :       2898 : Registry::~Registry()
     325                 :            : {
     326                 :            :     LOGCALL_DTOR(API, "Registry");
     327                 :            : 
     328                 :            :     // Note - we don't need to do anything special in this destructor, but it
     329                 :            :     // does need to be explicitly defined because the definition of the
     330                 :            :     // internals is not visible externally, which results in an error if the
     331                 :            :     // compiler tries to generate a default destructor.
     332                 :       1449 : }
     333                 :            : 
     334                 :            : void
     335                 :          5 : Registry::register_weighting_scheme(const Xapian::Weight &wt)
     336                 :            : {
     337                 :            :     LOGCALL_VOID(API, "Xapian::Registry::register_weighting_scheme", wt.name());
     338                 :          5 :     register_object(internal->wtschemes, internal->wtschemes_short, wt);
     339                 :          4 : }
     340                 :            : 
     341                 :            : const Xapian::Weight *
     342                 :      10415 : Registry::get_weighting_scheme(const string & name) const
     343                 :            : {
     344                 :            :     LOGCALL(API, const Xapian::Weight *, "Xapian::Registry::get_weighting_scheme", name);
     345 [ +  - ][ -  + ]:      10415 :     if (!name.empty() && C_islower(name[0])) {
                 [ -  + ]
     346         [ #  # ]:          0 :         const Xapian::Weight * wt_short = lookup_object(internal->wtschemes_short, name);
     347         [ #  # ]:          0 :         if (wt_short != NULL) {
     348                 :          0 :             RETURN(wt_short);
     349                 :            :         }
     350                 :            :     }
     351         [ +  - ]:      10415 :     RETURN(lookup_object(internal->wtschemes, name));
     352                 :            : }
     353                 :            : 
     354                 :            : void
     355                 :          6 : Registry::register_posting_source(const Xapian::PostingSource &source)
     356                 :            : {
     357                 :            :     LOGCALL_VOID(API, "Xapian::Registry::register_posting_source", source.name());
     358                 :          6 :     register_object(internal->postingsources, source);
     359                 :          5 : }
     360                 :            : 
     361                 :            : const Xapian::PostingSource *
     362                 :         44 : Registry::get_posting_source(const string & name) const
     363                 :            : {
     364                 :            :     LOGCALL(API, const Xapian::PostingSource *, "Xapian::Registry::get_posting_source", name);
     365         [ +  - ]:         44 :     RETURN(lookup_object(internal->postingsources, name));
     366                 :            : }
     367                 :            : 
     368                 :            : void
     369                 :          2 : Registry::register_match_spy(const Xapian::MatchSpy &spy)
     370                 :            : {
     371                 :            :     LOGCALL_VOID(API, "Xapian::Registry::register_match_spy", spy.name());
     372                 :          2 :     register_object(internal->matchspies, spy);
     373                 :          1 : }
     374                 :            : 
     375                 :            : const Xapian::MatchSpy *
     376                 :          5 : Registry::get_match_spy(const string & name) const
     377                 :            : {
     378                 :            :     LOGCALL(API, const Xapian::MatchSpy *, "Xapian::Registry::get_match_spy", name);
     379         [ +  - ]:          5 :     RETURN(lookup_object(internal->matchspies, name));
     380                 :            : }
     381                 :            : 
     382                 :            : void
     383                 :          0 : Registry::register_lat_long_metric(const Xapian::LatLongMetric &metric)
     384                 :            : {
     385                 :            :     LOGCALL_VOID(API, "Xapian::Registry::register_lat_long_metric", metric.name());
     386                 :          0 :     register_object(internal->lat_long_metrics, metric);
     387                 :          0 : }
     388                 :            : 
     389                 :            : const Xapian::LatLongMetric *
     390                 :          1 : Registry::get_lat_long_metric(const string & name) const
     391                 :            : {
     392                 :            :     LOGCALL(API, const Xapian::LatLongMetric *, "Xapian::Registry::get_lat_long_metric", name);
     393         [ +  - ]:          1 :     RETURN(lookup_object(internal->lat_long_metrics, name));
     394                 :            : }
     395                 :            : 
     396                 :            : }

Generated by: LCOV version 1.11