#include "KinoSearch/Util/ToolSet.h"
#define KINO_WANT_TERMSTEPPER_VTABLE
#include "KinoSearch/Index/TermStepper.r"
#include "KinoSearch/Schema.r"
#include "KinoSearch/Index/Term.r"
#include "KinoSearch/Index/TermInfo.r"
#include "KinoSearch/Store/InStream.r"
#include "KinoSearch/Store/OutStream.r"
#include "KinoSearch/Util/StringHelper.h"
/* Read in a term's worth of data from the input stream.
*/
static void
read_term_text(TermStepper *self, InStream *instream);
/* Read in a TermInfo from the input stream.
*/
static void
read_tinfo(TermStepper *self, InStream *instream);
TermStepper*
TermStepper_new(const ByteBuf *field, u32_t skip_interval,
bool_t is_index)
{
CREATE(self, TermStepper, TERMSTEPPER);
/* assign */
self->field = BB_CLONE(field);
self->is_index = is_index;
self->skip_interval = skip_interval;
/* init */
self->term = NULL;
/* derive */
self->tinfo = TInfo_new(0,0,0,0);
return self;
}
void
TermStepper_destroy(TermStepper *self)
{
REFCOUNT_DEC(self->field);
REFCOUNT_DEC(self->term);
REFCOUNT_DEC(self->tinfo);
free(self);
}
ByteBuf*
TermStepper_to_string(TermStepper *self)
{
if (self->term == NULL) {
return BB_new_str("(empty)", 7);
}
else {
ByteBuf *string = Term_To_String(self->term);
ByteBuf *tinfo_str = TInfo_To_String(self->tinfo);
BB_Cat_Str(string, "\n", 1);
StrHelp_add_indent(tinfo_str, 4);
BB_Cat_BB(string, tinfo_str);
REFCOUNT_DEC(tinfo_str);
return string;
}
}
void
TermStepper_write_record(TermStepper* self, OutStream *outstream,
const char *term_text,
size_t term_text_len,
const char *last_text,
size_t last_text_len,
TermInfo* tinfo,
TermInfo *last_tinfo,
u64_t lex_filepos, u64_t last_lex_filepos)
{
/* count how many bytes the strings share at the top */
const i32_t overlap = StrHelp_string_diff(last_text, term_text,
last_text_len, term_text_len);
const char *const diff_start_str = term_text + overlap;
const size_t diff_len = term_text_len - overlap;
/* write number of common bytes and common bytes */
OutStream_Write_VInt(outstream, overlap);
OutStream_Write_String(outstream, diff_start_str, diff_len);
/* write doc_freq */
OutStream_Write_VInt(outstream, tinfo->doc_freq);
/* delta encode filepointers */
OutStream_Write_VLong(outstream,
(tinfo->post_filepos - last_tinfo->post_filepos) );
/* write skipdata */
if (tinfo->doc_freq >= self->skip_interval)
OutStream_Write_VInt(outstream, tinfo->skip_filepos);
/* the .lexx index file gets a pointer to the location of the primary */
if (self->is_index)
OutStream_Write_VLong(outstream, (lex_filepos - last_lex_filepos));
}
void
TermStepper_read_record(TermStepper *self, InStream *instream)
{
read_term_text(self, instream);
read_tinfo(self, instream);
}
void
TermStepper_reset(TermStepper *self)
{
REFCOUNT_DEC(self->term);
self->term = NULL;
TInfo_Reset(self->tinfo);
}
void
TermStepper_set_term(TermStepper *self, const Term *term)
{
if (term == NULL) {
REFCOUNT_DEC(self->term);
self->term = NULL;
}
else if (self->term == NULL) {
self->term = (Term*)Term_Clone(term);
}
else {
Term_Copy(self->term, term);
}
}
void
TermStepper_set_tinfo(TermStepper *self, const TermInfo *tinfo)
{
TInfo_Copy(self->tinfo, tinfo);
}
void
TermStepper_copy(TermStepper *self, TermStepper *other)
{
TermStepper_Set_Term(self, other->term);
TermStepper_Set_TInfo(self, other->tinfo);
}
static void
read_term_text(TermStepper *self, InStream *instream)
{
const u32_t text_overlap = InStream_Read_VInt(instream);
const u32_t finish_chars_len = InStream_Read_VInt(instream);
const u32_t total_text_len = text_overlap + finish_chars_len;
ByteBuf *term_text;
/* get the term's text buffer and allocate space */
if (self->term == NULL) {
ByteBuf empty = BYTEBUF_BLANK;
self->term = Term_new(self->field, &empty);
}
term_text = self->term->text;
BB_GROW(term_text, total_text_len);
/* set the term text */
term_text->len = total_text_len;
InStream_Read_BytesO(instream, term_text->ptr, text_overlap,
finish_chars_len);
/* null-terminate */
*(term_text->ptr + total_text_len) = '\0';
}
void
read_tinfo(TermStepper *self, InStream *instream)
{
TermInfo *const tinfo = self->tinfo;
/* read doc freq */
tinfo->doc_freq = InStream_Read_VInt(instream);
/* adjust file pointer. */
tinfo->post_filepos += InStream_Read_VLong(instream);
/* read skip data */
if (tinfo->doc_freq >= self->skip_interval)
tinfo->skip_filepos = InStream_Read_VInt(instream);
else
tinfo->skip_filepos = 0;
/* read filepointer to main enum if this is an index enum */
if (self->is_index)
tinfo->index_filepos += InStream_Read_VLong(instream);
}
/* Copyright 2006-2007 Marvin Humphrey
*
* This program is free software; you can redistribute it and/or modify
* under the same terms as Perl itself.
*/