[monkeydoc] Merge/add monkeydoc to master.
[mono.git] / mcs / tools / monkeydoc / Lucene.Net / Lucene.Net / Index / SegmentTermPositions.cs
1 /* 
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  * 
9  * http://www.apache.org/licenses/LICENSE-2.0
10  * 
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 using System;
19
20 using IndexInput = Mono.Lucene.Net.Store.IndexInput;
21
22 namespace Mono.Lucene.Net.Index
23 {
24         
25         public sealed class SegmentTermPositions:SegmentTermDocs, TermPositions
26         {
27                 private IndexInput proxStream;
28                 private int proxCount;
29                 private int position;
30                 
31                 // the current payload length
32                 private int payloadLength;
33                 // indicates whether the payload of the currend position has
34                 // been read from the proxStream yet
35                 private bool needToLoadPayload;
36                 
37                 // these variables are being used to remember information
38                 // for a lazy skip
39                 private long lazySkipPointer = - 1;
40                 private int lazySkipProxCount = 0;
41                 
42                 internal SegmentTermPositions(SegmentReader p):base(p)
43                 {
44                         this.proxStream = null; // the proxStream will be cloned lazily when nextPosition() is called for the first time
45                 }
46                 
47                 internal override void  Seek(TermInfo ti, Term term)
48                 {
49                         base.Seek(ti, term);
50                         if (ti != null)
51                                 lazySkipPointer = ti.proxPointer;
52                         
53                         lazySkipProxCount = 0;
54                         proxCount = 0;
55                         payloadLength = 0;
56                         needToLoadPayload = false;
57                 }
58                 
59                 public override void  Close()
60                 {
61                         base.Close();
62                         if (proxStream != null)
63                                 proxStream.Close();
64                 }
65                 
66                 public int NextPosition()
67                 {
68                         if (currentFieldOmitTermFreqAndPositions)
69                         // This field does not store term freq, positions, payloads
70                                 return 0;
71                         // perform lazy skips if neccessary
72                         LazySkip();
73                         proxCount--;
74                         return position += ReadDeltaPosition();
75                 }
76                 
77                 private int ReadDeltaPosition()
78                 {
79                         int delta = proxStream.ReadVInt();
80                         if (currentFieldStoresPayloads)
81                         {
82                                 // if the current field stores payloads then
83                                 // the position delta is shifted one bit to the left.
84                                 // if the LSB is set, then we have to read the current
85                                 // payload length
86                                 if ((delta & 1) != 0)
87                                 {
88                                         payloadLength = proxStream.ReadVInt();
89                                 }
90                                 delta = SupportClass.Number.URShift(delta, 1);
91                                 needToLoadPayload = true;
92                         }
93                         return delta;
94                 }
95                 
96                 protected internal override void  SkippingDoc()
97                 {
98                         // we remember to skip a document lazily
99                         lazySkipProxCount += freq;
100                 }
101                 
102                 public override bool Next()
103                 {
104                         // we remember to skip the remaining positions of the current
105                         // document lazily
106                         lazySkipProxCount += proxCount;
107                         
108                         if (base.Next())
109                         {
110                                 // run super
111                                 proxCount = freq; // note frequency
112                                 position = 0; // reset position
113                                 return true;
114                         }
115                         return false;
116                 }
117                 
118                 public override int Read(int[] docs, int[] freqs)
119                 {
120                         throw new System.NotSupportedException("TermPositions does not support processing multiple documents in one call. Use TermDocs instead.");
121                 }
122                 
123                 
124                 /// <summary>Called by super.skipTo(). </summary>
125                 protected internal override void  SkipProx(long proxPointer, int payloadLength)
126                 {
127                         // we save the pointer, we might have to skip there lazily
128                         lazySkipPointer = proxPointer;
129                         lazySkipProxCount = 0;
130                         proxCount = 0;
131                         this.payloadLength = payloadLength;
132                         needToLoadPayload = false;
133                 }
134                 
135                 private void  SkipPositions(int n)
136                 {
137                         System.Diagnostics.Debug.Assert(!currentFieldOmitTermFreqAndPositions);
138                         for (int f = n; f > 0; f--)
139                         {
140                                 // skip unread positions
141                                 ReadDeltaPosition();
142                                 SkipPayload();
143                         }
144                 }
145                 
146                 private void  SkipPayload()
147                 {
148                         if (needToLoadPayload && payloadLength > 0)
149                         {
150                                 proxStream.Seek(proxStream.GetFilePointer() + payloadLength);
151                         }
152                         needToLoadPayload = false;
153                 }
154                 
155                 // It is not always neccessary to move the prox pointer
156                 // to a new document after the freq pointer has been moved.
157                 // Consider for example a phrase query with two terms:
158                 // the freq pointer for term 1 has to move to document x
159                 // to answer the question if the term occurs in that document. But
160                 // only if term 2 also matches document x, the positions have to be
161                 // read to figure out if term 1 and term 2 appear next
162                 // to each other in document x and thus satisfy the query.
163                 // So we move the prox pointer lazily to the document
164                 // as soon as positions are requested.
165                 private void  LazySkip()
166                 {
167                         if (proxStream == null)
168                         {
169                                 // clone lazily
170                                 proxStream = (IndexInput) parent.core.proxStream.Clone();
171                         }
172                         
173                         // we might have to skip the current payload
174                         // if it was not read yet
175                         SkipPayload();
176                         
177                         if (lazySkipPointer != - 1)
178                         {
179                                 proxStream.Seek(lazySkipPointer);
180                                 lazySkipPointer = - 1;
181                         }
182                         
183                         if (lazySkipProxCount != 0)
184                         {
185                                 SkipPositions(lazySkipProxCount);
186                                 lazySkipProxCount = 0;
187                         }
188                 }
189                 
190                 public int GetPayloadLength()
191                 {
192                         return payloadLength;
193                 }
194                 
195                 public byte[] GetPayload(byte[] data, int offset)
196                 {
197                         if (!needToLoadPayload)
198                         {
199                                 throw new System.IO.IOException("Either no payload exists at this term position or an attempt was made to load it more than once.");
200                         }
201                         
202                         // read payloads lazily
203                         byte[] retArray;
204                         int retOffset;
205                         if (data == null || data.Length - offset < payloadLength)
206                         {
207                                 // the array is too small to store the payload data,
208                                 // so we allocate a new one
209                                 retArray = new byte[payloadLength];
210                                 retOffset = 0;
211                         }
212                         else
213                         {
214                                 retArray = data;
215                                 retOffset = offset;
216                         }
217                         proxStream.ReadBytes(retArray, retOffset, payloadLength);
218                         needToLoadPayload = false;
219                         return retArray;
220                 }
221                 
222                 public bool IsPayloadAvailable()
223                 {
224                         return needToLoadPayload && payloadLength > 0;
225                 }
226         }
227 }