| /* |
| * 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; |
| |
| namespace Lucene.Net.Index |
| { |
| internal sealed class SegmentTermPositions : SegmentTermDocs, TermPositions |
| { |
| private IndexInput proxStream; |
| private int proxCount; |
| private int position; |
| |
| // the current payload length |
| private int payloadLength; |
| // indicates whether the payload of the currend position has |
| // been read from the proxStream yet |
| private bool needToLoadPayload; |
| |
| // these variables are being used to remember information |
| // for a lazy skip |
| private long lazySkipPointer = - 1; |
| private int lazySkipProxCount = 0; |
| |
| internal SegmentTermPositions(SegmentReader p):base(p) |
| { |
| this.proxStream = null; // the proxStream will be cloned lazily when nextPosition() is called for the first time |
| } |
| |
| internal override void Seek(TermInfo ti, Term term) |
| { |
| base.Seek(ti, term); |
| if (ti != null) |
| lazySkipPointer = ti.proxPointer; |
| |
| lazySkipProxCount = 0; |
| proxCount = 0; |
| payloadLength = 0; |
| needToLoadPayload = false; |
| } |
| |
| protected override void Dispose(bool disposing) |
| { |
| base.Dispose(disposing); |
| if (proxStream != null) |
| proxStream.Dispose(); |
| } |
| |
| public int NextPosition() |
| { |
| if (currentFieldOmitTermFreqAndPositions) |
| // This field does not store term freq, positions, payloads |
| return 0; |
| // perform lazy skips if neccessary |
| LazySkip(); |
| proxCount--; |
| return position += ReadDeltaPosition(); |
| } |
| |
| private int ReadDeltaPosition() |
| { |
| int delta = proxStream.ReadVInt(); |
| if (currentFieldStoresPayloads) |
| { |
| // if the current field stores payloads then |
| // the position delta is shifted one bit to the left. |
| // if the LSB is set, then we have to read the current |
| // payload length |
| if ((delta & 1) != 0) |
| { |
| payloadLength = proxStream.ReadVInt(); |
| } |
| delta = Number.URShift(delta, 1); |
| needToLoadPayload = true; |
| } |
| return delta; |
| } |
| |
| protected internal override void SkippingDoc() |
| { |
| // we remember to skip a document lazily |
| lazySkipProxCount += freq; |
| } |
| |
| public override bool Next() |
| { |
| // we remember to skip the remaining positions of the current |
| // document lazily |
| lazySkipProxCount += proxCount; |
| |
| if (base.Next()) |
| { |
| // run super |
| proxCount = freq; // note frequency |
| position = 0; // reset position |
| return true; |
| } |
| return false; |
| } |
| |
| public override int Read(int[] docs, int[] freqs) |
| { |
| throw new System.NotSupportedException("TermPositions does not support processing multiple documents in one call. Use TermDocs instead."); |
| } |
| |
| |
| /// <summary>Called by super.skipTo(). </summary> |
| protected internal override void SkipProx(long proxPointer, int payloadLength) |
| { |
| // we save the pointer, we might have to skip there lazily |
| lazySkipPointer = proxPointer; |
| lazySkipProxCount = 0; |
| proxCount = 0; |
| this.payloadLength = payloadLength; |
| needToLoadPayload = false; |
| } |
| |
| private void SkipPositions(int n) |
| { |
| System.Diagnostics.Debug.Assert(!currentFieldOmitTermFreqAndPositions); |
| for (int f = n; f > 0; f--) |
| { |
| // skip unread positions |
| ReadDeltaPosition(); |
| SkipPayload(); |
| } |
| } |
| |
| private void SkipPayload() |
| { |
| if (needToLoadPayload && payloadLength > 0) |
| { |
| proxStream.Seek(proxStream.FilePointer + payloadLength); |
| } |
| needToLoadPayload = false; |
| } |
| |
| // It is not always neccessary to move the prox pointer |
| // to a new document after the freq pointer has been moved. |
| // Consider for example a phrase query with two terms: |
| // the freq pointer for term 1 has to move to document x |
| // to answer the question if the term occurs in that document. But |
| // only if term 2 also matches document x, the positions have to be |
| // read to figure out if term 1 and term 2 appear next |
| // to each other in document x and thus satisfy the query. |
| // So we move the prox pointer lazily to the document |
| // as soon as positions are requested. |
| private void LazySkip() |
| { |
| if (proxStream == null) |
| { |
| // clone lazily |
| proxStream = (IndexInput) parent.core.proxStream.Clone(); |
| } |
| |
| // we might have to skip the current payload |
| // if it was not read yet |
| SkipPayload(); |
| |
| if (lazySkipPointer != - 1) |
| { |
| proxStream.Seek(lazySkipPointer); |
| lazySkipPointer = - 1; |
| } |
| |
| if (lazySkipProxCount != 0) |
| { |
| SkipPositions(lazySkipProxCount); |
| lazySkipProxCount = 0; |
| } |
| } |
| |
| public int PayloadLength |
| { |
| get { return payloadLength; } |
| } |
| |
| public byte[] GetPayload(byte[] data, int offset) |
| { |
| if (!needToLoadPayload) |
| { |
| throw new System.IO.IOException("Either no payload exists at this term position or an attempt was made to load it more than once."); |
| } |
| |
| // read payloads lazily |
| byte[] retArray; |
| int retOffset; |
| if (data == null || data.Length - offset < payloadLength) |
| { |
| // the array is too small to store the payload data, |
| // so we allocate a new one |
| retArray = new byte[payloadLength]; |
| retOffset = 0; |
| } |
| else |
| { |
| retArray = data; |
| retOffset = offset; |
| } |
| proxStream.ReadBytes(retArray, retOffset, payloadLength); |
| needToLoadPayload = false; |
| return retArray; |
| } |
| |
| public bool IsPayloadAvailable |
| { |
| get { return needToLoadPayload && payloadLength > 0; } |
| } |
| } |
| } |