1 /* glass_positionlist.cc: A position list in a glass database.
3 * Copyright (C) 2004,2005,2006,2008,2009,2010,2013,2017 Olly Betts
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.
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.
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
23 #include "glass_positionlist.h"
25 #include <xapian/types.h>
27 #include "bitstream.h"
36 GlassPositionListTable::pack(string
& s
,
37 const Xapian::VecCOW
<Xapian::termpos
> & vec
) const
39 LOGCALL_VOID(DB
, "GlassPositionListTable::pack", s
| vec
);
42 pack_uint(s
, vec
.back());
46 wr
.encode(vec
[0], vec
.back());
47 wr
.encode(vec
.size() - 2, vec
.back() - vec
[0]);
48 wr
.encode_interpolative(vec
, 0, vec
.size() - 1);
54 GlassPositionListTable::positionlist_count(Xapian::docid did
,
55 const string
& term
) const
57 LOGCALL(DB
, Xapian::termcount
, "GlassPositionListTable::positionlist_count", did
| term
);
60 if (!get_exact_entry(make_key(did
, term
), data
)) {
64 const char * pos
= data
.data();
65 const char * end
= pos
+ data
.size();
66 Xapian::termpos pos_last
;
67 if (!unpack_uint(&pos
, end
, &pos_last
)) {
68 throw Xapian::DatabaseCorruptError("Position list data corrupt");
71 // Special case for single entry position list.
75 // Skip the header we just read.
76 BitReader
rd(pos
, end
);
77 Xapian::termpos pos_first
= rd
.decode(pos_last
);
78 Xapian::termpos pos_size
= rd
.decode(pos_last
- pos_first
) + 2;
82 ///////////////////////////////////////////////////////////////////////////
85 GlassBasePositionList::get_approx_size() const
87 LOGCALL(DB
, Xapian::termcount
, "GlassBasePositionList::get_approx_size", NO_ARGS
);
92 GlassBasePositionList::get_position() const
94 LOGCALL(DB
, Xapian::termpos
, "GlassBasePositionList::get_position", NO_ARGS
);
100 GlassBasePositionList::next()
102 LOGCALL(DB
, bool, "GlassBasePositionList::next", NO_ARGS
);
103 if (rare(!have_started
)) {
105 return current_pos
<= last
;
107 if (current_pos
== last
) {
110 current_pos
= rd
.decode_interpolative_next();
115 GlassBasePositionList::skip_to(Xapian::termpos termpos
)
117 LOGCALL(DB
, bool, "GlassBasePositionList::skip_to", termpos
);
119 if (termpos
>= last
) {
120 if (termpos
== last
) {
126 while (current_pos
< termpos
) {
127 if (current_pos
== last
) {
130 current_pos
= rd
.decode_interpolative_next();
135 GlassPositionList::GlassPositionList(const string
& data
)
137 LOGCALL_CTOR(DB
, "GlassPositionList", data
);
139 have_started
= false;
142 // There's no positional information for this term.
149 const char* pos
= data
.data();
150 const char* end
= pos
+ data
.size();
151 Xapian::termpos pos_last
;
152 if (!unpack_uint(&pos
, end
, &pos_last
)) {
153 throw Xapian::DatabaseCorruptError("Position list data corrupt");
157 // Special case for single entry position list.
159 current_pos
= last
= pos_last
;
163 // Copy the rest of the data and lazily decode from that copy.
164 pos_data
.assign(pos
, end
);
166 rd
.init(pos_data
.data(), pos_data
.size());
167 Xapian::termpos pos_first
= rd
.decode(pos_last
);
168 Xapian::termpos pos_size
= rd
.decode(pos_last
- pos_first
) + 2;
169 rd
.decode_interpolative(0, pos_size
- 1, pos_first
, pos_last
);
172 current_pos
= pos_first
;
175 GlassPositionList::GlassPositionList(const GlassTable
* table
,
179 LOGCALL_CTOR(DB
, "GlassPositionList", table
| did
| term
);
181 have_started
= false;
183 if (!table
->get_exact_entry(GlassPositionListTable::make_key(did
, term
),
185 // There's no positional information for this term.
192 const char* pos
= pos_data
.data();
193 const char* end
= pos
+ pos_data
.size();
194 Xapian::termpos pos_last
;
195 if (!unpack_uint(&pos
, end
, &pos_last
)) {
196 throw Xapian::DatabaseCorruptError("Position list data corrupt");
200 // Special case for single entry position list.
202 current_pos
= last
= pos_last
;
207 Xapian::termpos pos_first
= rd
.decode(pos_last
);
208 Xapian::termpos pos_size
= rd
.decode(pos_last
- pos_first
) + 2;
209 rd
.decode_interpolative(0, pos_size
- 1, pos_first
, pos_last
);
212 current_pos
= pos_first
;
216 GlassRePositionList::read_data(Xapian::docid did
,
219 LOGCALL_VOID(DB
, "GlassRePositionList::read_data", table
| did
| term
);
221 have_started
= false;
223 if (!cursor
.find_exact(GlassPositionListTable::make_key(did
, term
))) {
224 // There's no positional information for this term.
231 const char* pos
= cursor
.current_tag
.data();
232 const char* end
= pos
+ cursor
.current_tag
.size();
233 Xapian::termpos pos_last
;
234 if (!unpack_uint(&pos
, end
, &pos_last
)) {
235 throw Xapian::DatabaseCorruptError("Position list data corrupt");
239 // Special case for single entry position list.
241 current_pos
= last
= pos_last
;
246 Xapian::termpos pos_first
= rd
.decode(pos_last
);
247 Xapian::termpos pos_size
= rd
.decode(pos_last
- pos_first
) + 2;
248 rd
.decode_interpolative(0, pos_size
- 1, pos_first
, pos_last
);
251 current_pos
= pos_first
;