Branch data Line data Source code
1 : : /** @file multi_alltermslist.cc
2 : : * @brief Class for merging AllTermsList objects from subdatabases.
3 : : */
4 : : /* Copyright (C) 2007,2008,2009 Olly Betts
5 : : *
6 : : * This program is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU General Public License as published by
8 : : * the Free Software Foundation; either version 2 of the License, or
9 : : * (at your option) any later version.
10 : : *
11 : : * This program is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : * GNU General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with this program; if not, write to the Free Software
18 : : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : : */
20 : :
21 : : #include <config.h>
22 : :
23 : : #include "multialltermslist.h"
24 : :
25 : : #include <xapian/error.h>
26 : :
27 : : #include "omassert.h"
28 : :
29 : : #include <algorithm>
30 : :
31 : : using namespace std;
32 : :
33 : : /// Comparison functor which orders TermList* by ascending term name.
34 : : struct CompareTermListsByTerm {
35 : : /// Order by ascending term name.
36 : 151 : bool operator()(const TermList *a, const TermList *b) {
37 : 151 : return a->get_termname() > b->get_termname();
38 : : }
39 : : };
40 : :
41 : : template<class CLASS> struct delete_ptr {
42 [ + - ]: 6 : void operator()(CLASS *p) { delete p; }
43 : : };
44 : :
45 : 105 : MultiAllTermsList::MultiAllTermsList(const vector<Xapian::Internal::RefCntPtr<Xapian::Database::Internal> > & dbs,
46 : 105 : const string & prefix)
47 : : {
48 : : // The 0 and 1 cases should be handled by our caller.
49 : : AssertRel(dbs.size(), >=, 2);
50 : 105 : termlists.reserve(dbs.size());
51 : : try {
52 : 105 : vector<Xapian::Internal::RefCntPtr<Xapian::Database::Internal> >::const_iterator i;
53 [ + + ][ # # ]: 351 : for (i = dbs.begin(); i != dbs.end(); ++i) {
54 : 246 : termlists.push_back((*i)->open_allterms(prefix));
55 : : }
56 : 0 : } catch (...) {
57 : 0 : for_each(termlists.begin(), termlists.end(), delete_ptr<TermList>());
58 : 0 : throw;
59 : : }
60 : 105 : }
61 : :
62 : 105 : MultiAllTermsList::~MultiAllTermsList()
63 : : {
64 : 105 : for_each(termlists.begin(), termlists.end(), delete_ptr<TermList>());
65 [ + - ][ # # ]: 105 : }
[ # # ]
66 : :
67 : : string
68 : 157 : MultiAllTermsList::get_termname() const
69 : : {
70 : 157 : return current_term;
71 : : }
72 : :
73 : : Xapian::doccount
74 : 64 : MultiAllTermsList::get_termfreq() const
75 : : {
76 [ - + ]: 64 : if (termlists.empty()) return 0;
77 : 64 : vector<TermList *>::const_iterator i = termlists.begin();
78 : 64 : Xapian::doccount total_tf = (*i)->get_termfreq();
79 [ + + ]: 152 : while (++i != termlists.end()) {
80 [ + + ]: 88 : if ((*i)->get_termname() == current_term)
81 : 12 : total_tf += (*i)->get_termfreq();
82 : : }
83 : 64 : return total_tf;
84 : : }
85 : :
86 : : Xapian::termcount
87 : 0 : MultiAllTermsList::get_collection_freq() const
88 : : {
89 [ # # ]: 0 : if (termlists.empty()) return 0;
90 : 0 : vector<TermList *>::const_iterator i = termlists.begin();
91 : 0 : Xapian::termcount total_cf = (*i)->get_collection_freq();
92 [ # # ]: 0 : while (++i != termlists.end()) {
93 [ # # ]: 0 : if ((*i)->get_termname() == current_term)
94 : 0 : total_cf += (*i)->get_collection_freq();
95 : : }
96 : 0 : return total_cf;
97 : : }
98 : :
99 : : TermList *
100 : 196 : MultiAllTermsList::next()
101 : : {
102 [ + + ]: 196 : if (current_term.empty()) {
103 : : // Make termlists into a heap so that the one (or one of the ones) with
104 : : // earliest sorting term is at the top of the heap.
105 : 105 : vector<TermList*>::iterator i = termlists.begin();
106 [ + + ]: 351 : while (i != termlists.end()) {
107 : 246 : (*i)->next();
108 [ + + ]: 246 : if ((*i)->at_end()) {
109 [ + - ]: 114 : delete *i;
110 : 114 : i = termlists.erase(i);
111 : : } else {
112 : 132 : ++i;
113 : : }
114 : : }
115 : : make_heap(termlists.begin(), termlists.end(),
116 : 105 : CompareTermListsByTerm());
117 : : } else {
118 : : // Advance to the next termname.
119 [ + + ][ + + ]: 115 : do {
[ + + ][ # # ]
[ + + ]
120 : 115 : TermList * tl = termlists.front();
121 : : pop_heap(termlists.begin(), termlists.end(),
122 : 115 : CompareTermListsByTerm());
123 : 115 : tl->next();
124 [ + + ]: 115 : if (tl->at_end()) {
125 [ + - ]: 46 : delete tl;
126 : 46 : termlists.pop_back();
127 : : } else {
128 : 69 : termlists.back() = tl;
129 : : push_heap(termlists.begin(), termlists.end(),
130 : 69 : CompareTermListsByTerm());
131 : : }
132 : : } while (!termlists.empty() &&
133 : 106 : termlists.front()->get_termname() == current_term);
134 : : }
135 : :
136 [ + + ]: 196 : if (termlists.size() <= 1) {
137 [ + + ]: 96 : if (termlists.empty()) return NULL;
138 : 68 : TermList * tl = termlists[0];
139 : 68 : termlists.clear();
140 : 68 : return tl;
141 : : }
142 : :
143 : 100 : current_term = termlists.front()->get_termname();
144 : 196 : return NULL;
145 : : }
146 : :
147 : : TermList *
148 : 15 : MultiAllTermsList::skip_to(const std::string &term)
149 : : {
150 : : // Assume the skip is likely to be a long distance, and rebuild the heap
151 : : // from scratch. FIXME: It would be useful to profile this against an
152 : : // approach more like that next() uses if this ever gets heavy use.
153 : 15 : vector<TermList*>::iterator i = termlists.begin();
154 [ + + ]: 45 : while (i != termlists.end()) {
155 : 30 : (*i)->skip_to(term);
156 [ + + ]: 30 : if ((*i)->at_end()) {
157 [ + - ]: 12 : delete *i;
158 : 12 : i = termlists.erase(i);
159 : : } else {
160 : 18 : ++i;
161 : : }
162 : : }
163 : :
164 [ + + ]: 15 : if (termlists.size() <= 1) {
165 [ + - ]: 6 : if (termlists.empty()) return NULL;
166 : 0 : TermList * tl = termlists[0];
167 : 0 : termlists.clear();
168 : 0 : return tl;
169 : : }
170 : :
171 : 9 : make_heap(termlists.begin(), termlists.end(), CompareTermListsByTerm());
172 : :
173 : 9 : current_term = termlists.front()->get_termname();
174 : 15 : return NULL;
175 : : }
176 : :
177 : : bool
178 : 143 : MultiAllTermsList::at_end() const
179 : : {
180 : 143 : return termlists.empty();
181 : : }
|