Branch data Line data Source code
1 : : /* flint_positionlist.cc: A position list in a flint database.
2 : : *
3 : : * Copyright (C) 2004,2005,2006,2008,2010 Olly Betts
4 : : *
5 : : * This program is free software; you can redistribute it and/or
6 : : * modify it under the terms of the GNU General Public License as
7 : : * published by the Free Software Foundation; either version 2 of the
8 : : * License, or (at your option) any later version.
9 : : *
10 : : * This program is distributed in the hope that it will be useful,
11 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : : * GNU General Public License for more details.
14 : : *
15 : : * You should have received a copy of the GNU General Public License
16 : : * along with this program; if not, write to the Free Software
17 : : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
18 : : * USA
19 : : */
20 : :
21 : : #include <config.h>
22 : :
23 : : #include "flint_positionlist.h"
24 : :
25 : : #include <xapian/types.h>
26 : :
27 : : #include "bitstream.h"
28 : : #include "debuglog.h"
29 : : #include "flint_utils.h"
30 : :
31 : : #include <string>
32 : : #include <vector>
33 : :
34 : : using namespace std;
35 : :
36 : : void
37 : 754078 : FlintPositionListTable::set_positionlist(Xapian::docid did,
38 : : const string & tname,
39 : : Xapian::PositionIterator pos,
40 : : const Xapian::PositionIterator &pos_end,
41 : : bool check_for_update)
42 : : {
43 : : LOGCALL_VOID(DB, "FlintPositionList::set_positionlist", did | tname | pos | pos_end | check_for_update);
44 : : Assert(pos != pos_end);
45 : :
46 : : // FIXME: avoid the need for this copy!
47 : 754078 : vector<Xapian::termpos> poscopy(pos, pos_end);
48 : :
49 : 754078 : string key = make_key(did, tname);
50 : :
51 : 754078 : string s = F_pack_uint(poscopy.back());
52 : :
53 [ + + ]: 754078 : if (poscopy.size() > 1) {
54 : 18773 : BitWriter wr(s);
55 : 18773 : wr.encode(poscopy[0], poscopy.back());
56 : 18773 : wr.encode(poscopy.size() - 2, poscopy.back() - poscopy[0]);
57 : 18773 : wr.encode_interpolative(poscopy, 0, poscopy.size() - 1);
58 : 18773 : swap(s, wr.freeze());
59 : : }
60 : :
61 [ + + ]: 754078 : if (check_for_update) {
62 : 46 : string old_tag;
63 [ + + + + ]: 46 : if (get_exact_entry(key, old_tag) && s == old_tag)
[ + + ]
64 [ + + ]: 46 : return;
65 : : }
66 [ + + ][ + + ]: 754078 : add(key, s);
67 : : }
68 : :
69 : : Xapian::termcount
70 : 11239 : FlintPositionListTable::positionlist_count(Xapian::docid did,
71 : : const string & term) const
72 : : {
73 : : LOGCALL_VOID(DB, "FlintPositionListTable::positionlist_count", did | term);
74 : :
75 : 11239 : string data;
76 [ + + ]: 11239 : if (!get_exact_entry(F_pack_uint_preserving_sort(did) + term, data)) {
77 : : // There's no positional information for this term.
78 : 10109 : return 0;
79 : : }
80 : :
81 : 1130 : const char * pos = data.data();
82 : 1130 : const char * end = pos + data.size();
83 : : Xapian::termpos pos_last;
84 [ - + ]: 1130 : if (!F_unpack_uint(&pos, end, &pos_last)) {
85 : 0 : throw Xapian::DatabaseCorruptError("Position list data corrupt");
86 : : }
87 [ + + ]: 1130 : if (pos == end) {
88 : : // Special case for single entry position list.
89 : 977 : return 1;
90 : : }
91 : :
92 : : // Skip the header we just read.
93 : 153 : BitReader rd(data, pos - data.data());
94 : 153 : Xapian::termpos pos_first = rd.decode(pos_last);
95 : 153 : Xapian::termpos pos_size = rd.decode(pos_last - pos_first) + 2;
96 : 11239 : return pos_size;
97 : : }
98 : :
99 : : ///////////////////////////////////////////////////////////////////////////
100 : :
101 : : bool
102 : 48241 : FlintPositionList::read_data(const FlintTable * table, Xapian::docid did,
103 : : const string & tname)
104 : : {
105 : : LOGCALL_VOID(DB, "FlintPositionList::read_data", table | did | tname);
106 : :
107 : 48241 : have_started = false;
108 : 48241 : positions.clear();
109 : :
110 : 48241 : string data;
111 [ + + ]: 48241 : if (!table->get_exact_entry(F_pack_uint_preserving_sort(did) + tname, data)) {
112 : : // There's no positional information for this term.
113 : 41139 : current_pos = positions.begin();
114 : 41139 : return false;
115 : : }
116 : :
117 : 7102 : const char * pos = data.data();
118 : 7102 : const char * end = pos + data.size();
119 : : Xapian::termpos pos_last;
120 [ - + ]: 7102 : if (!F_unpack_uint(&pos, end, &pos_last)) {
121 : 0 : throw Xapian::DatabaseCorruptError("Position list data corrupt");
122 : : }
123 [ + + ]: 7102 : if (pos == end) {
124 : : // Special case for single entry position list.
125 : 6207 : positions.push_back(pos_last);
126 : 6207 : current_pos = positions.begin();
127 : 6207 : return true;
128 : : }
129 : : // Skip the header we just read.
130 : 895 : BitReader rd(data, pos - data.data());
131 : 895 : Xapian::termpos pos_first = rd.decode(pos_last);
132 : 895 : Xapian::termpos pos_size = rd.decode(pos_last - pos_first) + 2;
133 : 895 : positions.resize(pos_size);
134 : 895 : positions[0] = pos_first;
135 : 895 : positions.back() = pos_last;
136 : 895 : rd.decode_interpolative(positions, 0, pos_size - 1);
137 : :
138 : 895 : current_pos = positions.begin();
139 : 48241 : return true;
140 : : }
141 : :
142 : : Xapian::termcount
143 : 5400 : FlintPositionList::get_size() const
144 : : {
145 : : LOGCALL(DB, Xapian::termcount, "FlintPositionList::get_size", NO_ARGS);
146 : 5400 : RETURN(positions.size());
147 : : }
148 : :
149 : : Xapian::termpos
150 : 26476 : FlintPositionList::get_position() const
151 : : {
152 : : LOGCALL(DB, Xapian::termpos, "FlintPositionList::get_position", NO_ARGS);
153 : : Assert(have_started);
154 : 26476 : RETURN(*current_pos);
155 : : }
156 : :
157 : : void
158 : 71137 : FlintPositionList::next()
159 : : {
160 : : LOGCALL_VOID(DB, "FlintPositionList::next", NO_ARGS);
161 : :
162 [ + + ]: 71137 : if (!have_started) {
163 : 46664 : have_started = true;
164 : : } else {
165 : : Assert(!at_end());
166 : 24473 : ++current_pos;
167 : : }
168 : 71137 : }
169 : :
170 : : void
171 : 1477 : FlintPositionList::skip_to(Xapian::termpos termpos)
172 : : {
173 : : LOGCALL_VOID(DB, "FlintPositionList::skip_to", termpos);
174 [ + + ]: 1477 : if (!have_started) {
175 : 1385 : have_started = true;
176 : : }
177 [ + + ][ + + ]: 1786 : while (!at_end() && *current_pos < termpos) ++current_pos;
[ + + ]
178 : 1477 : }
179 : :
180 : : bool
181 : 74400 : FlintPositionList::at_end() const
182 : : {
183 : : LOGCALL(DB, bool, "FlintPositionList::at_end", NO_ARGS);
184 : 74400 : RETURN(current_pos == positions.end());
185 : : }
|