Lucene.Net  3.0.3
Lucene.Net is a .NET port of the Java Lucene Indexing Library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties
BufferedIndexInput.cs
Go to the documentation of this file.
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 namespace Lucene.Net.Store
21 {
22 
24  public abstract class BufferedIndexInput : IndexInput, System.ICloneable
25  {
26 
28  public const int BUFFER_SIZE = 1024;
29 
30  private int _bufferSize = BUFFER_SIZE;
31 
32  protected internal byte[] buffer;
33 
34  private long bufferStart = 0; // position in file of buffer
35  private int bufferLength = 0; // end of valid bytes
36  private int bufferPosition = 0; // next byte to read
37 
38  public override byte ReadByte()
39  {
40  if (bufferPosition >= bufferLength)
41  Refill();
42  return buffer[bufferPosition++];
43  }
44 
45  protected BufferedIndexInput()
46  {
47  }
48 
50  protected BufferedIndexInput(int bufferSize)
51  {
52  CheckBufferSize(bufferSize);
53  this._bufferSize = bufferSize;
54  }
55 
57  public virtual void SetBufferSize(int newSize)
58  {
59  System.Diagnostics.Debug.Assert(buffer == null || _bufferSize == buffer.Length, "buffer=" + buffer + " bufferSize=" + _bufferSize + " buffer.length=" +(buffer != null ? buffer.Length: 0));
60  if (newSize != _bufferSize)
61  {
62  CheckBufferSize(newSize);
63  _bufferSize = newSize;
64  if (buffer != null)
65  {
66  // Resize the existing buffer and carefully save as
67  // many bytes as possible starting from the current
68  // bufferPosition
69  byte[] newBuffer = new byte[newSize];
70  int leftInBuffer = bufferLength - bufferPosition;
71  int numToCopy;
72  if (leftInBuffer > newSize)
73  numToCopy = newSize;
74  else
75  numToCopy = leftInBuffer;
76  Array.Copy(buffer, bufferPosition, newBuffer, 0, numToCopy);
77  bufferStart += bufferPosition;
78  bufferPosition = 0;
79  bufferLength = numToCopy;
80  NewBuffer(newBuffer);
81  }
82  }
83  }
84 
85  protected internal virtual void NewBuffer(byte[] newBuffer)
86  {
87  // Subclasses can do something here
88  buffer = newBuffer;
89  }
90 
93  public virtual int BufferSize
94  {
95  get { return _bufferSize; }
96  }
97 
98  private void CheckBufferSize(int bufferSize)
99  {
100  if (bufferSize <= 0)
101  throw new System.ArgumentException("bufferSize must be greater than 0 (got " + bufferSize + ")");
102  }
103 
104  public override void ReadBytes(byte[] b, int offset, int len)
105  {
106  ReadBytes(b, offset, len, true);
107  }
108 
109  public override void ReadBytes(byte[] b, int offset, int len, bool useBuffer)
110  {
111 
112  if (len <= (bufferLength - bufferPosition))
113  {
114  // the buffer contains enough data to satisfy this request
115  if (len > 0)
116  // to allow b to be null if len is 0...
117  Array.Copy(buffer, bufferPosition, b, offset, len);
118  bufferPosition += len;
119  }
120  else
121  {
122  // the buffer does not have enough data. First serve all we've got.
123  int available = bufferLength - bufferPosition;
124  if (available > 0)
125  {
126  Array.Copy(buffer, bufferPosition, b, offset, available);
127  offset += available;
128  len -= available;
129  bufferPosition += available;
130  }
131  // and now, read the remaining 'len' bytes:
132  if (useBuffer && len < _bufferSize)
133  {
134  // If the amount left to read is small enough, and
135  // we are allowed to use our buffer, do it in the usual
136  // buffered way: fill the buffer and copy from it:
137  Refill();
138  if (bufferLength < len)
139  {
140  // Throw an exception when refill() could not read len bytes:
141  Array.Copy(buffer, 0, b, offset, bufferLength);
142  throw new System.IO.IOException("read past EOF");
143  }
144  else
145  {
146  Array.Copy(buffer, 0, b, offset, len);
147  bufferPosition = len;
148  }
149  }
150  else
151  {
152  // The amount left to read is larger than the buffer
153  // or we've been asked to not use our buffer -
154  // there's no performance reason not to read it all
155  // at once. Note that unlike the previous code of
156  // this function, there is no need to do a seek
157  // here, because there's no need to reread what we
158  // had in the buffer.
159  long after = bufferStart + bufferPosition + len;
160  if (after > Length())
161  throw new System.IO.IOException("read past EOF");
162  ReadInternal(b, offset, len);
163  bufferStart = after;
164  bufferPosition = 0;
165  bufferLength = 0; // trigger refill() on read
166  }
167  }
168  }
169 
170  private void Refill()
171  {
172  long start = bufferStart + bufferPosition;
173  long end = start + _bufferSize;
174  if (end > Length())
175  // don't read past EOF
176  end = Length();
177  int newLength = (int) (end - start);
178  if (newLength <= 0)
179  throw new System.IO.IOException("read past EOF");
180 
181  if (buffer == null)
182  {
183  NewBuffer(new byte[_bufferSize]); // allocate buffer lazily
184  SeekInternal(bufferStart);
185  }
186  ReadInternal(buffer, 0, newLength);
187  bufferLength = newLength;
188  bufferStart = start;
189  bufferPosition = 0;
190  }
191 
201  public abstract void ReadInternal(byte[] b, int offset, int length);
202 
203  public override long FilePointer
204  {
205  get { return bufferStart + bufferPosition; }
206  }
207 
208  public override void Seek(long pos)
209  {
210  if (pos >= bufferStart && pos < (bufferStart + bufferLength))
211  bufferPosition = (int) (pos - bufferStart);
212  // seek within buffer
213  else
214  {
215  bufferStart = pos;
216  bufferPosition = 0;
217  bufferLength = 0; // trigger refill() on read()
218  SeekInternal(pos);
219  }
220  }
221 
227  public abstract void SeekInternal(long pos);
228 
229  public override System.Object Clone()
230  {
232 
233  clone.buffer = null;
234  clone.bufferLength = 0;
235  clone.bufferPosition = 0;
236  clone.bufferStart = FilePointer;
237 
238  return clone;
239  }
240  }
241 }