The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

parcel Lucy;

/** Invert documents.
 *
 * Inverter's role is to prepare the content of a Doc for addition to various
 * DataWriters, by associating fields with FieldTypes, inverting their
 * content when appropriate, and marshalling them into an iterable form.
 */

class Lucy::Index::Inverter inherits Clownfish::Obj {

    Schema        *schema;
    Segment       *segment;
    Doc           *doc;
    Vector        *entries;    /* Entries for the current Doc. */
    Vector        *entry_pool; /* Cached entry per field. */
    InverterEntry *current;    /* Current entry while iterating. */
    InverterEntry *blank;      /* Used when iterator is exhausted. */
    float          boost;
    int32_t        tick;
    bool           sorted;

    inert incremented Inverter*
    new(Schema *schema, Segment *segment);

    inert Inverter*
    init(Inverter *self, Schema *schema, Segment *segment);

    /** Invert the document, first calling [](cfish:.Set_Doc), then [](cfish:.Add_Field) for
     * each field in the Doc.
     */
    public void
    Invert_Doc(Inverter *self, Doc *doc);

    /** Set the object's `doc` member.  Calls [](cfish:.Clear) as side
     * effect.
     */
    public void
    Set_Doc(Inverter *self, Doc *doc);

    /** Set the object's `boost` member.
     */
    public void
    Set_Boost(Inverter *self, float boost);

    /** Add a field to the Inverter.  If the field is indexed/analyzed, invert
     * it.
     *
     * The InverterEntry's value should have already been set to the field's
     * value when [](cfish:.Add_Field) is called.
     */
    void
    Add_Field(Inverter *self, InverterEntry *entry);

    /** Remove the cached Doc and everything derived from it.
     */
    public void
    Clear(Inverter *self);

    /** Reset the iterator and prepare to cycle through any fields that have
     * been added.
     *
     * @return the number of fields which will be iterated over.
     */
    public uint32_t
    Iterate(Inverter *self);

    /** Proceed to the next field.  Fields are iterated in order of Segment
     * field number.
     */
    public int32_t
    Next(Inverter *self);

    /** Return the current doc, or NULL if there isn't one.
     */
    public nullable Doc*
    Get_Doc(Inverter *self);

    /** Return the current boost.
     */
    public float
    Get_Boost(Inverter *self);

    /** Return the current field's name, or NULL if the iterator is exhausted.
     */
    public nullable String*
    Get_Field_Name(Inverter *self);

    /** Return the current field's value, or NULL if the iterator is
     * exhausted.
     */
    public nullable Obj*
    Get_Value(Inverter *self);

    /** Return the FieldType for the current field, or NULL if the iterator is
     * exhausted.
     */
    public nullable FieldType*
    Get_Type(Inverter *self);

    /** Return the Analyzer for the current field, or NULL if the iterator is
     * exhausted.
     */
    public nullable Analyzer*
    Get_Analyzer(Inverter *self);

    /** Return the Analyzer for the current field, or NULL if the iterator is
     * exhausted.
     */
    public nullable Similarity*
    Get_Similarity(Inverter *self);

    /** Return the Inversion for the current field, provided that that field
     * is indexed; return NULL if the iterator is exhausted.
     */
    public nullable Inversion*
    Get_Inversion(Inverter *self);

    public void
    Destroy(Inverter *self);
}

/** Cached information about fields.
 *
 * Inverter needs to check certain field characteristics frequently.  Since
 * field definitions are unchanging, we cache them in an InverterEntry object.
 */
final class Lucy::Index::Inverter::InverterEntry nickname InvEntry
    inherits Clownfish::Obj {

    int32_t      field_num;
    String      *field;
    Obj         *value;
    Inversion   *inversion;
    FieldType   *type;
    Analyzer    *analyzer;
    Similarity  *sim;
    bool         indexed;
    bool         highlightable;

    inert incremented InverterEntry*
    new(Schema *schema = NULL, String *field_name, int32_t field_num);

    inert InverterEntry*
    init(InverterEntry *self = NULL, Schema *schema,
         String *field_name, int32_t field_num);

    public int32_t
    Compare_To(InverterEntry *self, Obj *other);

    /** Expunge all transient data.
     */
    void
    Clear(InverterEntry *self);

    public void
    Destroy(InverterEntry *self);
}