2 * @brief Class for looking up user subclasses during unserialisation.
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
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"
34 #include "stringutils.h"
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.
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();
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
)));
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
101 swap(p
, r
.first
->second
);
105 T
* clone
= obj
.clone();
107 throw Xapian::InvalidOperationError("Unable to register object - clone() method returned NULL");
110 r
.first
->second
= clone
;
115 register_object(map
<string
, T
*> & registry1
, map
<string
, T
*> & registry2
,
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");
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
145 swap(p
, r1
.first
->second
);
149 T
* clone
= obj
.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
;
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()) {
174 Registry::Internal::Internal()
179 Registry::Internal::~Internal()
181 clear_weighting_schemes();
182 clear_posting_sources();
184 clear_lat_long_metrics();
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
;
261 Registry::Internal::clear_weighting_schemes()
263 map
<string
, Xapian::Weight
*>::const_iterator i
;
264 for (i
= wtschemes
.begin(); i
!= wtschemes
.end(); ++i
) {
270 Registry::Internal::clear_posting_sources()
272 map
<string
, Xapian::PostingSource
*>::const_iterator i
;
273 for (i
= postingsources
.begin(); i
!= postingsources
.end(); ++i
) {
279 Registry::Internal::clear_match_spies()
281 map
<string
, Xapian::MatchSpy
*>::const_iterator i
;
282 for (i
= matchspies
.begin(); i
!= matchspies
.end(); ++i
) {
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
) {
296 Registry::Registry(const Registry
& other
)
297 : internal(other
.internal
)
299 LOGCALL_CTOR(API
, "Registry", other
);
303 Registry::operator=(const Registry
& other
)
305 LOGCALL(API
, Xapian::Registry
&, "Xapian::Registry::operator=", other
);
306 internal
= other
.internal
;
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.
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
) {
343 RETURN(lookup_object(internal
->wtschemes
, name
));
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
));
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
));
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
));