Add Weight::create() and Weight::create_from_parameters()
[xapian.git] / xapian-core / api / registry.cc
blobde78393ff9008c53c0f253586c043b3a037c8737
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
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.
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.
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
22 #include <config.h>
24 #include "xapian/registry.h"
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"
33 #include "debuglog.h"
34 #include "stringutils.h"
36 #include <algorithm>
37 #include <map>
38 #include <string>
40 using namespace std;
42 class Xapian::Registry::Internal : public Xapian::Internal::intrusive_base {
43 friend class Xapian::Registry;
45 /// Registered weighting schemes.
46 std::map<std::string, Xapian::Weight *> wtschemes;
48 /// Registered weighting schemes by their short names. E.g. "bm25".
49 std::map<std::string, Xapian::Weight *> wtschemes_short;
51 /// Registered external posting sources.
52 std::map<std::string, Xapian::PostingSource *> postingsources;
54 /// Registered match spies.
55 std::map<std::string, Xapian::MatchSpy *> matchspies;
57 /// Registered lat-long metrics.
58 std::map<std::string, Xapian::LatLongMetric *> lat_long_metrics;
60 /// Add the standard subclasses provided in the API.
61 void add_defaults();
63 /// Clear all registered weighting schemes.
64 void clear_weighting_schemes();
66 /// Clear all registered posting sources.
67 void clear_posting_sources();
69 /// Clear all registered match spies.
70 void clear_match_spies();
72 /// Clear all registered lat-long metrics.
73 void clear_lat_long_metrics();
75 public:
76 Internal();
77 ~Internal();
80 template<class T>
81 static inline void
82 register_object(map<string, T*> & registry, const T & obj)
84 string name = obj.name();
85 if (rare(name.empty())) {
86 throw Xapian::InvalidOperationError("Unable to register object - name() method returned empty string");
89 pair<typename map<string, T *>::iterator, bool> r;
90 r = registry.insert(make_pair(name, static_cast<T*>(NULL)));
91 if (!r.second) {
92 // Existing element with this key, so replace the pointer with NULL
93 // and delete the existing pointer.
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 T * p = NULL;
101 swap(p, r.first->second);
102 delete p;
105 T * clone = obj.clone();
106 if (rare(!clone)) {
107 throw Xapian::InvalidOperationError("Unable to register object - clone() method returned NULL");
110 r.first->second = clone;
113 template<class T>
114 static inline void
115 register_object(map<string, T*> & registry1, map<string, T*> & registry2,
116 const T & obj)
118 string name = obj.name();
119 if (rare(name.empty())) {
120 throw Xapian::InvalidOperationError("Unable to register object - name() method returned empty string");
123 pair<typename map<string, T *>::iterator, bool> r1;
124 r1 = registry1.insert(make_pair(name, static_cast<T*>(NULL)));
126 pair<typename map<string, T *>::iterator, bool> r2;
127 string short_name = obj.short_name();
128 if (!short_name.empty()) {
129 r2 = registry2.insert(make_pair(short_name, static_cast<T*>(NULL)));
130 if (r1.second != r2.second || (!r1.second && r2.first->second != r1.first->second)) {
131 throw Xapian::InvalidOperationError("Unable to register object - weighting scheme with the same name but a different short name already registered");
135 if (!r1.second) {
136 // Existing element with this key, so replace the pointer with NULL
137 // and delete the existing pointer.
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 T * p = NULL;
145 swap(p, r1.first->second);
146 delete p;
149 T * clone = obj.clone();
150 if (rare(!clone)) {
151 throw Xapian::InvalidOperationError("Unable to register object - clone() method returned NULL");
154 r1.first->second = clone;
156 if (!short_name.empty()) {
157 r2.first->second = clone;
161 template<class T>
162 static inline const T *
163 lookup_object(map<string, T*> registry, const string & name)
165 typename map<string, T*>::const_iterator i = registry.find(name);
166 if (i == registry.end()) {
167 return NULL;
169 return i->second;
172 namespace Xapian {
174 Registry::Internal::Internal()
176 add_defaults();
179 Registry::Internal::~Internal()
181 clear_weighting_schemes();
182 clear_posting_sources();
183 clear_match_spies();
184 clear_lat_long_metrics();
187 void
188 Registry::Internal::add_defaults()
190 Xapian::Weight * weighting_scheme;
191 weighting_scheme = new Xapian::BB2Weight;
192 wtschemes[weighting_scheme->name()] = weighting_scheme;
193 wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
194 weighting_scheme = new Xapian::BM25Weight;
195 wtschemes[weighting_scheme->name()] = weighting_scheme;
196 wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
197 weighting_scheme = new Xapian::BM25PlusWeight;
198 wtschemes[weighting_scheme->name()] = weighting_scheme;
199 wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
200 weighting_scheme = new Xapian::BoolWeight;
201 wtschemes[weighting_scheme->name()] = weighting_scheme;
202 wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
203 weighting_scheme = new Xapian::CoordWeight;
204 wtschemes[weighting_scheme->name()] = weighting_scheme;
205 wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
206 weighting_scheme = new Xapian::TradWeight;
207 wtschemes[weighting_scheme->name()] = weighting_scheme;
208 wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
209 weighting_scheme = new Xapian::TfIdfWeight;
210 wtschemes[weighting_scheme->name()] = weighting_scheme;
211 wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
212 weighting_scheme = new Xapian::InL2Weight;
213 wtschemes[weighting_scheme->name()] = weighting_scheme;
214 wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
215 weighting_scheme = new Xapian::IfB2Weight;
216 wtschemes[weighting_scheme->name()] = weighting_scheme;
217 wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
218 weighting_scheme = new Xapian::IneB2Weight;
219 wtschemes[weighting_scheme->name()] = weighting_scheme;
220 wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
221 weighting_scheme = new Xapian::DLHWeight;
222 wtschemes[weighting_scheme->name()] = weighting_scheme;
223 wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
224 weighting_scheme = new Xapian::PL2PlusWeight;
225 wtschemes[weighting_scheme->name()] = weighting_scheme;
226 wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
227 weighting_scheme = new Xapian::PL2Weight;
228 wtschemes[weighting_scheme->name()] = weighting_scheme;
229 wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
230 weighting_scheme = new Xapian::DPHWeight;
231 wtschemes[weighting_scheme->name()] = weighting_scheme;
232 wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
233 weighting_scheme = new Xapian::LMWeight;
234 wtschemes[weighting_scheme->name()] = weighting_scheme;
235 wtschemes_short[weighting_scheme->short_name()] = weighting_scheme;
237 Xapian::PostingSource * source;
238 source = new Xapian::ValueWeightPostingSource(0);
239 postingsources[source->name()] = source;
240 source = new Xapian::DecreasingValueWeightPostingSource(0);
241 postingsources[source->name()] = source;
242 source = new Xapian::ValueMapPostingSource(0);
243 postingsources[source->name()] = source;
244 source = new Xapian::FixedWeightPostingSource(0.0);
245 postingsources[source->name()] = source;
246 source = new Xapian::LatLongDistancePostingSource(0,
247 Xapian::LatLongCoords(),
248 Xapian::GreatCircleMetric());
249 postingsources[source->name()] = source;
251 Xapian::MatchSpy * spy;
252 spy = new Xapian::ValueCountMatchSpy();
253 matchspies[spy->name()] = spy;
255 Xapian::LatLongMetric * metric;
256 metric = new Xapian::GreatCircleMetric();
257 lat_long_metrics[metric->name()] = metric;
260 void
261 Registry::Internal::clear_weighting_schemes()
263 map<string, Xapian::Weight*>::const_iterator i;
264 for (i = wtschemes.begin(); i != wtschemes.end(); ++i) {
265 delete i->second;
269 void
270 Registry::Internal::clear_posting_sources()
272 map<string, Xapian::PostingSource *>::const_iterator i;
273 for (i = postingsources.begin(); i != postingsources.end(); ++i) {
274 delete i->second;
278 void
279 Registry::Internal::clear_match_spies()
281 map<string, Xapian::MatchSpy *>::const_iterator i;
282 for (i = matchspies.begin(); i != matchspies.end(); ++i) {
283 delete i->second;
287 void
288 Registry::Internal::clear_lat_long_metrics()
290 map<string, Xapian::LatLongMetric *>::const_iterator i;
291 for (i = lat_long_metrics.begin(); i != lat_long_metrics.end(); ++i) {
292 delete i->second;
296 Registry::Registry(const Registry & other)
297 : internal(other.internal)
299 LOGCALL_CTOR(API, "Registry", other);
302 Registry &
303 Registry::operator=(const Registry & other)
305 LOGCALL(API, Xapian::Registry &, "Xapian::Registry::operator=", other);
306 internal = other.internal;
307 RETURN(*this);
310 Registry::Registry()
311 : internal(new Registry::Internal())
313 LOGCALL_CTOR(API, "Registry", NO_ARGS);
316 Registry::~Registry()
318 LOGCALL_DTOR(API, "Registry");
320 // Note - we don't need to do anything special in this destructor, but it
321 // does need to be explicitly defined because the definition of the
322 // internals is not visible externally, which results in an error if the
323 // compiler tries to generate a default destructor.
326 void
327 Registry::register_weighting_scheme(const Xapian::Weight &wt)
329 LOGCALL_VOID(API, "Xapian::Registry::register_weighting_scheme", wt.name());
330 register_object(internal->wtschemes, internal->wtschemes_short, wt);
333 const Xapian::Weight *
334 Registry::get_weighting_scheme(const string & name) const
336 LOGCALL(API, const Xapian::Weight *, "Xapian::Registry::get_weighting_scheme", name);
337 if (!name.empty() && C_islower(name[0])) {
338 const Xapian::Weight * wt_short = lookup_object(internal->wtschemes_short, name);
339 if (wt_short != NULL) {
340 RETURN(wt_short);
343 RETURN(lookup_object(internal->wtschemes, name));
346 void
347 Registry::register_posting_source(const Xapian::PostingSource &source)
349 LOGCALL_VOID(API, "Xapian::Registry::register_posting_source", source.name());
350 register_object(internal->postingsources, source);
353 const Xapian::PostingSource *
354 Registry::get_posting_source(const string & name) const
356 LOGCALL(API, const Xapian::PostingSource *, "Xapian::Registry::get_posting_source", name);
357 RETURN(lookup_object(internal->postingsources, name));
360 void
361 Registry::register_match_spy(const Xapian::MatchSpy &spy)
363 LOGCALL_VOID(API, "Xapian::Registry::register_match_spy", spy.name());
364 register_object(internal->matchspies, spy);
367 const Xapian::MatchSpy *
368 Registry::get_match_spy(const string & name) const
370 LOGCALL(API, const Xapian::MatchSpy *, "Xapian::Registry::get_match_spy", name);
371 RETURN(lookup_object(internal->matchspies, name));
374 void
375 Registry::register_lat_long_metric(const Xapian::LatLongMetric &metric)
377 LOGCALL_VOID(API, "Xapian::Registry::register_lat_long_metric", metric.name());
378 register_object(internal->lat_long_metrics, metric);
381 const Xapian::LatLongMetric *
382 Registry::get_lat_long_metric(const string & name) const
384 LOGCALL(API, const Xapian::LatLongMetric *, "Xapian::Registry::get_lat_long_metric", name);
385 RETURN(lookup_object(internal->lat_long_metrics, name));