/* * 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. */ using System; using Lucene.Net.Support; using IndexInput = Lucene.Net.Store.IndexInput; using BitVector = Lucene.Net.Util.BitVector; namespace Lucene.Net.Index { internal class SegmentTermDocs : TermDocs { protected internal SegmentReader parent; protected internal IndexInput freqStream; protected internal int count; protected internal int df; protected internal BitVector deletedDocs; internal int doc = 0; internal int freq; private readonly int skipInterval; private readonly int maxSkipLevels; private DefaultSkipListReader skipListReader; private long freqBasePointer; private long proxBasePointer; private long skipPointer; private bool haveSkipped; protected internal bool currentFieldStoresPayloads; protected internal bool currentFieldOmitTermFreqAndPositions; private bool isDisposed; public /*protected internal*/ SegmentTermDocs(SegmentReader parent) { this.parent = parent; this.freqStream = (IndexInput) parent.core.freqStream.Clone(); lock (parent) { this.deletedDocs = parent.deletedDocs; } this.skipInterval = parent.core.GetTermsReader().SkipInterval; this.maxSkipLevels = parent.core.GetTermsReader().MaxSkipLevels; } public virtual void Seek(Term term) { TermInfo ti = parent.core.GetTermsReader().Get(term); Seek(ti, term); } public virtual void Seek(TermEnum termEnum) { TermInfo ti; Term term; // use comparison of fieldinfos to verify that termEnum belongs to the same segment as this SegmentTermDocs if (termEnum is SegmentTermEnum && ((SegmentTermEnum) termEnum).fieldInfos == parent.core.fieldInfos) { // optimized case var segmentTermEnum = ((SegmentTermEnum) termEnum); term = segmentTermEnum.Term; ti = segmentTermEnum.TermInfo(); } else { // punt case term = termEnum.Term; ti = parent.core.GetTermsReader().Get(term); } Seek(ti, term); } internal virtual void Seek(TermInfo ti, Term term) { count = 0; FieldInfo fi = parent.core.fieldInfos.FieldInfo(term.Field); currentFieldOmitTermFreqAndPositions = (fi != null) && fi.omitTermFreqAndPositions; currentFieldStoresPayloads = (fi != null) && fi.storePayloads; if (ti == null) { df = 0; } else { df = ti.docFreq; doc = 0; freqBasePointer = ti.freqPointer; proxBasePointer = ti.proxPointer; skipPointer = freqBasePointer + ti.skipOffset; freqStream.Seek(freqBasePointer); haveSkipped = false; } } public void Dispose() { Dispose(true); } [Obsolete("Use Dispose() instead")] public void Close() { Dispose(); } protected virtual void Dispose(bool disposing) { if (isDisposed) return; freqStream.Dispose(); if (skipListReader != null) skipListReader.Dispose(); isDisposed = true; } public int Doc { get { return doc; } } public int Freq { get { return freq; } } protected internal virtual void SkippingDoc() { } public virtual bool Next() { while (true) { if (count == df) return false; int docCode = freqStream.ReadVInt(); if (currentFieldOmitTermFreqAndPositions) { doc += docCode; freq = 1; } else { doc += Number.URShift(docCode, 1); // shift off low bit if ((docCode & 1) != 0) // if low bit is set freq = 1; // freq is one else freq = freqStream.ReadVInt(); // else read freq } count++; if (deletedDocs == null || !deletedDocs.Get(doc)) break; SkippingDoc(); } return true; } /// Optimized implementation. public virtual int Read(int[] docs, int[] freqs) { int length = docs.Length; if (currentFieldOmitTermFreqAndPositions) { return ReadNoTf(docs, freqs, length); } else { int i = 0; while (i < length && count < df) { // manually inlined call to next() for speed int docCode = freqStream.ReadVInt(); doc += Number.URShift(docCode, 1); // shift off low bit if ((docCode & 1) != 0) // if low bit is set freq = 1; // freq is one else freq = freqStream.ReadVInt(); // else read freq count++; if (deletedDocs == null || !deletedDocs.Get(doc)) { docs[i] = doc; freqs[i] = freq; ++i; } } return i; } } private int ReadNoTf(int[] docs, int[] freqs, int length) { int i = 0; while (i < length && count < df) { // manually inlined call to next() for speed doc += freqStream.ReadVInt(); count++; if (deletedDocs == null || !deletedDocs.Get(doc)) { docs[i] = doc; // Hardware freq to 1 when term freqs were not // stored in the index freqs[i] = 1; ++i; } } return i; } /// Overridden by SegmentTermPositions to skip in prox stream. protected internal virtual void SkipProx(long proxPointer, int payloadLength) { } /// Optimized implementation. public virtual bool SkipTo(int target) { if (df >= skipInterval) { // optimized case if (skipListReader == null) skipListReader = new DefaultSkipListReader((IndexInput) freqStream.Clone(), maxSkipLevels, skipInterval); // lazily clone if (!haveSkipped) { // lazily initialize skip stream skipListReader.Init(skipPointer, freqBasePointer, proxBasePointer, df, currentFieldStoresPayloads); haveSkipped = true; } int newCount = skipListReader.SkipTo(target); if (newCount > count) { freqStream.Seek(skipListReader.GetFreqPointer()); SkipProx(skipListReader.GetProxPointer(), skipListReader.GetPayloadLength()); doc = skipListReader.GetDoc(); count = newCount; } } // done skipping, now just scan do { if (!Next()) return false; } while (target > doc); return true; } } }