#include "KinoSearch/Util/ToolSet.h"
#define KINO_WANT_FIELDDOCCOLLATOR_VTABLE
#include "KinoSearch/Search/FieldDocCollator.r"
#include "KinoSearch/Search/FieldDoc.r"
#include "KinoSearch/Util/IntMap.r"
FieldDocCollator*
FDocCollator_new()
{
CREATE(self, FieldDocCollator, FIELDDOCCOLLATOR);
self->cap = 0;
self->size = 0;
self->sort_caches = NULL;
self->reversed = NULL;
return self;
}
void
FDocCollator_destroy(FieldDocCollator *self)
{
u32_t i;
for (i = 0; i < self->size; i++) {
REFCOUNT_DEC(self->sort_caches[i]);
}
free(self->sort_caches);
free(self->reversed);
free(self);
}
void
FDocCollator_add(FieldDocCollator *self, IntMap *sort_cache, bool_t rev)
{
/* allocate space */
if (self->size >= self->cap) {
self->cap += 10;
self->sort_caches
= REALLOCATE(self->sort_caches, self->cap, IntMap*);
self->reversed = REALLOCATE(self->reversed, self->cap, bool_t);
}
self->sort_caches[ self->size ] = REFCOUNT_INC(sort_cache);
self->reversed[ self->size ] = rev;
self->size++;
}
bool_t
FDocCollator_less_than(const void *va, const void *vb)
{
FieldDoc *const a = (FieldDoc*)va;
FieldDoc *const b = (FieldDoc*)vb;
FieldDocCollator *const self = a->collator; /* extract self */
return FDocCollator_compare(self, a->doc_num, a->score,
b->doc_num, b->score);
}
bool_t
FDocCollator_compare(FieldDocCollator *self, u32_t doc_num_a, float score_a,
u32_t doc_num_b, float score_b)
{
IntMap **const sort_caches = self->sort_caches;
bool_t *const reversed = self->reversed;
u32_t i;
for (i = 0; i < self->size; i++) {
/* TODO: unroll for speed */
const i32_t sort_num_a = IntMap_Get(sort_caches[i], doc_num_a);
const i32_t sort_num_b = IntMap_Get(sort_caches[i], doc_num_b);
if (sort_num_a != sort_num_b) {
/* This appears to be backwards, but it isn't. Things have to be
* inverted because we're comparing pre-prepared sort numbers.
*/
bool_t retval = sort_num_a > sort_num_b;
if (reversed[i])
return !retval;
else
return retval;
}
}
/* break ties by score, then by doc num, so sort is stable per reader */
if (score_a != score_b)
return score_a < score_b;
else
return doc_num_a < doc_num_b;
}
/* Copyright 2007 Marvin Humphrey
*
* This program is free software; you can redistribute it and/or modify
* under the same terms as Perl itself.
*/