static int8_t S_derive_action(SortRule *rule, SortCache *cache) { int32_t rule_type = SortRule_Get_Type(rule); bool reverse = !!SortRule_Get_Reverse(rule); if (rule_type == SortRule_SCORE) { return COMPARE_BY_SCORE + reverse; } else if (rule_type == SortRule_DOC_ID) { return COMPARE_BY_DOC_ID + reverse; } else if (rule_type == SortRule_FIELD) { if (cache) { int8_t width = SortCache_Get_Ord_Width(cache); switch (width) { case 1: return COMPARE_BY_ORD1 + reverse; case 2: return COMPARE_BY_ORD2 + reverse; case 4: return COMPARE_BY_ORD4 + reverse; case 8: return COMPARE_BY_ORD8 + reverse; case 16: if (SortCache_Get_Native_Ords(cache)) { return COMPARE_BY_NATIVE_ORD16 + reverse; } else { return COMPARE_BY_ORD16 + reverse; } case 32: if (SortCache_Get_Native_Ords(cache)) { return COMPARE_BY_NATIVE_ORD32 + reverse; } else { return COMPARE_BY_ORD32 + reverse; } default: THROW(ERR, "Unknown width: %i8", width); } } else { return AUTO_TIE; } } else { THROW(ERR, "Unrecognized SortRule type %i32", rule_type); } UNREACHABLE_RETURN(int8_t); }
HitQueue* HitQ_init(HitQueue *self, Schema *schema, SortSpec *sort_spec, uint32_t wanted) { HitQueueIVARS *const ivars = HitQ_IVARS(self); if (sort_spec) { VArray *rules = SortSpec_Get_Rules(sort_spec); uint32_t num_rules = VA_Get_Size(rules); uint32_t action_num = 0; if (!schema) { THROW(ERR, "Can't supply sort_spec without schema"); } ivars->need_values = false; ivars->num_actions = num_rules; ivars->actions = (uint8_t*)MALLOCATE(num_rules * sizeof(uint8_t)); ivars->field_types = (FieldType**)CALLOCATE(num_rules, sizeof(FieldType*)); for (uint32_t i = 0; i < num_rules; i++) { SortRule *rule = (SortRule*)VA_Fetch(rules, i); int32_t rule_type = SortRule_Get_Type(rule); bool reverse = SortRule_Get_Reverse(rule); if (rule_type == SortRule_SCORE) { ivars->actions[action_num++] = reverse ? COMPARE_BY_SCORE_REV : COMPARE_BY_SCORE; } else if (rule_type == SortRule_DOC_ID) { ivars->actions[action_num++] = reverse ? COMPARE_BY_DOC_ID_REV : COMPARE_BY_DOC_ID; } else if (rule_type == SortRule_FIELD) { String *field = SortRule_Get_Field(rule); FieldType *type = Schema_Fetch_Type(schema, field); if (type) { ivars->field_types[action_num] = (FieldType*)INCREF(type); ivars->actions[action_num++] = reverse ? COMPARE_BY_VALUE_REV : COMPARE_BY_VALUE; ivars->need_values = true; } else { // Skip over fields we don't know how to sort on. continue; } } else { THROW(ERR, "Unknown SortRule type: %i32", rule_type); } } } else { ivars->num_actions = 2; ivars->actions = (uint8_t*)MALLOCATE(ivars->num_actions * sizeof(uint8_t)); ivars->actions[0] = COMPARE_BY_SCORE; ivars->actions[1] = COMPARE_BY_DOC_ID; } return (HitQueue*)PriQ_init((PriorityQueue*)self, wanted); }
SortCollector* SortColl_init(SortCollector *self, Schema *schema, SortSpec *sort_spec, uint32_t wanted) { VArray *rules = sort_spec ? (VArray*)INCREF(SortSpec_Get_Rules(sort_spec)) : S_default_sort_rules(); uint32_t num_rules = VA_Get_Size(rules); // Validate. if (sort_spec && !schema) { THROW(ERR, "Can't supply a SortSpec without a Schema."); } if (!num_rules) { THROW(ERR, "Can't supply a SortSpec with no SortRules."); } // Init. Coll_init((Collector*)self); SortCollectorIVARS *const ivars = SortColl_IVARS(self); ivars->total_hits = 0; ivars->bubble_doc = INT32_MAX; ivars->bubble_score = F32_NEGINF; ivars->seg_doc_max = 0; // Assign. ivars->wanted = wanted; // Derive. ivars->hit_q = HitQ_new(schema, sort_spec, wanted); ivars->rules = rules; // absorb refcount. ivars->num_rules = num_rules; ivars->sort_caches = (SortCache**)CALLOCATE(num_rules, sizeof(SortCache*)); ivars->ord_arrays = (void**)CALLOCATE(num_rules, sizeof(void*)); ivars->actions = (uint8_t*)CALLOCATE(num_rules, sizeof(uint8_t)); // Build up an array of "actions" which we will execute during each call // to Collect(). Determine whether we need to track scores and field // values. ivars->need_score = false; ivars->need_values = false; for (uint32_t i = 0; i < num_rules; i++) { SortRule *rule = (SortRule*)VA_Fetch(rules, i); int32_t rule_type = SortRule_Get_Type(rule); ivars->actions[i] = S_derive_action(rule, NULL); if (rule_type == SortRule_SCORE) { ivars->need_score = true; } else if (rule_type == SortRule_FIELD) { CharBuf *field = SortRule_Get_Field(rule); FieldType *type = Schema_Fetch_Type(schema, field); if (!type || !FType_Sortable(type)) { THROW(ERR, "'%o' isn't a sortable field", field); } ivars->need_values = true; } } // Perform an optimization. So long as we always collect docs in // ascending order, Collect() will favor lower doc numbers -- so we may // not need to execute a final COMPARE_BY_DOC_ID action. ivars->num_actions = num_rules; if (ivars->actions[num_rules - 1] == COMPARE_BY_DOC_ID) { ivars->num_actions--; } // Override our derived actions with an action which will be excecuted // autmatically until the queue fills up. ivars->auto_actions = (uint8_t*)MALLOCATE(1); ivars->auto_actions[0] = wanted ? AUTO_ACCEPT : AUTO_REJECT; ivars->derived_actions = ivars->actions; ivars->actions = ivars->auto_actions; // Prepare a MatchDoc-in-waiting. VArray *values = ivars->need_values ? VA_new(num_rules) : NULL; float score = ivars->need_score ? F32_NEGINF : F32_NAN; ivars->bumped = MatchDoc_new(INT32_MAX, score, values); DECREF(values); return self; }