Branch data Line data Source code
1 : : /* brass_positionlist.cc: A position list in a brass database.
2 : : *
3 : : * Copyright (C) 2004,2005,2006,2008,2009,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 "brass_positionlist.h"
24 : :
25 : : #include <xapian/types.h>
26 : :
27 : : #include "bitstream.h"
28 : : #include "debuglog.h"
29 : : #include "pack.h"
30 : :
31 : : #include <string>
32 : : #include <vector>
33 : :
34 : : using namespace std;
35 : :
36 : : void
37 : 754067 : BrassPositionListTable::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, "BrassPositionList::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 : 754067 : vector<Xapian::termpos> poscopy(pos, pos_end);
48 : :
49 : 754067 : string key = make_key(did, tname);
50 : :
51 : 754067 : string s;
52 : 754067 : pack_uint(s, poscopy.back());
53 : :
54 [ + + ]: 754067 : if (poscopy.size() > 1) {
55 : 18773 : BitWriter wr(s);
56 : 18773 : wr.encode(poscopy[0], poscopy.back());
57 : 18773 : wr.encode(poscopy.size() - 2, poscopy.back() - poscopy[0]);
58 : 18773 : wr.encode_interpolative(poscopy, 0, poscopy.size() - 1);
59 : 18773 : swap(s, wr.freeze());
60 : : }
61 : :
62 [ + + ]: 754067 : if (check_for_update) {
63 : 46 : string old_tag;
64 [ + + + + ]: 46 : if (get_exact_entry(key, old_tag) && s == old_tag)
[ + + ]
65 [ + + ]: 46 : return;
66 : : }
67 [ + + ][ + + ]: 754067 : add(key, s);
68 : : }
69 : :
70 : : Xapian::termcount
71 : 11210 : BrassPositionListTable::positionlist_count(Xapian::docid did,
72 : : const string & term) const
73 : : {
74 : : LOGCALL_VOID(DB, "BrassPositionListTable::positionlist_count", did | term);
75 : :
76 : 11210 : string data;
77 [ + + ]: 11210 : if (!get_exact_entry(make_key(did, term), data)) {
78 : : // There's no positional information for this term.
79 : 10129 : return 0;
80 : : }
81 : :
82 : 1081 : const char * pos = data.data();
83 : 1081 : const char * end = pos + data.size();
84 : : Xapian::termpos pos_last;
85 [ - + ]: 1081 : if (!unpack_uint(&pos, end, &pos_last)) {
86 : 0 : throw Xapian::DatabaseCorruptError("Position list data corrupt");
87 : : }
88 [ + + ]: 1081 : if (pos == end) {
89 : : // Special case for single entry position list.
90 : 928 : return 1;
91 : : }
92 : :
93 : : // Skip the header we just read.
94 : 153 : BitReader rd(data, pos - data.data());
95 : 153 : Xapian::termpos pos_first = rd.decode(pos_last);
96 : 153 : Xapian::termpos pos_size = rd.decode(pos_last - pos_first) + 2;
97 : 11210 : return pos_size;
98 : : }
99 : :
100 : : ///////////////////////////////////////////////////////////////////////////
101 : :
102 : : bool
103 : 48067 : BrassPositionList::read_data(const BrassTable * table, Xapian::docid did,
104 : : const string & tname)
105 : : {
106 : : LOGCALL_VOID(DB, "BrassPositionList::read_data", table | did | tname);
107 : :
108 : 48067 : have_started = false;
109 : 48067 : positions.clear();
110 : :
111 : 48067 : string data;
112 [ + + ]: 48067 : if (!table->get_exact_entry(BrassPositionListTable::make_key(did, tname), data)) {
113 : : // There's no positional information for this term.
114 : 41259 : current_pos = positions.begin();
115 : 41259 : return false;
116 : : }
117 : :
118 : 6808 : const char * pos = data.data();
119 : 6808 : const char * end = pos + data.size();
120 : : Xapian::termpos pos_last;
121 [ - + ]: 6808 : if (!unpack_uint(&pos, end, &pos_last)) {
122 : 0 : throw Xapian::DatabaseCorruptError("Position list data corrupt");
123 : : }
124 [ + + ]: 6808 : if (pos == end) {
125 : : // Special case for single entry position list.
126 : 5913 : positions.push_back(pos_last);
127 : 5913 : current_pos = positions.begin();
128 : 5913 : return true;
129 : : }
130 : : // Skip the header we just read.
131 : 895 : BitReader rd(data, pos - data.data());
132 : 895 : Xapian::termpos pos_first = rd.decode(pos_last);
133 : 895 : Xapian::termpos pos_size = rd.decode(pos_last - pos_first) + 2;
134 : 895 : positions.resize(pos_size);
135 : 895 : positions[0] = pos_first;
136 : 895 : positions.back() = pos_last;
137 : 895 : rd.decode_interpolative(positions, 0, pos_size - 1);
138 : :
139 : 895 : current_pos = positions.begin();
140 : 48067 : return true;
141 : : }
142 : :
143 : : Xapian::termcount
144 : 5400 : BrassPositionList::get_size() const
145 : : {
146 : : LOGCALL(DB, Xapian::termcount, "BrassPositionList::get_size", NO_ARGS);
147 : 5400 : RETURN(positions.size());
148 : : }
149 : :
150 : : Xapian::termpos
151 : 26182 : BrassPositionList::get_position() const
152 : : {
153 : : LOGCALL(DB, Xapian::termpos, "BrassPositionList::get_position", NO_ARGS);
154 : : Assert(have_started);
155 : 26182 : RETURN(*current_pos);
156 : : }
157 : :
158 : : void
159 : 70669 : BrassPositionList::next()
160 : : {
161 : : LOGCALL_VOID(DB, "BrassPositionList::next", NO_ARGS);
162 : :
163 [ + + ]: 70669 : if (!have_started) {
164 : 46490 : have_started = true;
165 : : } else {
166 : : Assert(!at_end());
167 : 24179 : ++current_pos;
168 : : }
169 : 70669 : }
170 : :
171 : : void
172 : 1477 : BrassPositionList::skip_to(Xapian::termpos termpos)
173 : : {
174 : : LOGCALL_VOID(DB, "BrassPositionList::skip_to", termpos);
175 [ + + ]: 1477 : if (!have_started) {
176 : 1385 : have_started = true;
177 : : }
178 [ + + ][ + + ]: 1786 : while (!at_end() && *current_pos < termpos) ++current_pos;
[ + + ]
179 : 1477 : }
180 : :
181 : : bool
182 : 73932 : BrassPositionList::at_end() const
183 : : {
184 : : LOGCALL(DB, bool, "BrassPositionList::at_end", NO_ARGS);
185 : 73932 : RETURN(current_pos == positions.end());
186 : : }
|