blob: 6844a99d9d767a3b2097e3917ea36f0bf6def3ba [file] [log] [blame]
using System;
using System.Diagnostics;
namespace Lucene.Net.Util
{
/*
* 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.
*/
public static class RollingBuffer
{
public interface Resettable
{
void Reset();
}
}
/// <summary>
/// Acts like forever growing T[], but internally uses a
/// circular buffer to reuse instances of T.
///
/// @lucene.internal
/// </summary>
public abstract class RollingBuffer<T>
where T : RollingBuffer.Resettable
{
private T[] Buffer = new T[8];
// Next array index to write to:
private int NextWrite;
// Next position to write:
private int NextPos;
// How many valid Position are held in the
// array:
private int Count;
protected RollingBuffer()
{
for (var idx = 0; idx < Buffer.Length; idx++)
{
Buffer[idx] = NewInstance(); // TODO GIVE ROLLING BUFFER A DELEGATE FOR NEW INSTANCE
}
}
protected RollingBuffer(Func<T> factory)
{
for (int idx = 0; idx < Buffer.Length; idx++)
{
Buffer[idx] = factory();
}
}
protected internal abstract T NewInstance();
public virtual void Reset()
{
NextWrite--;
while (Count > 0)
{
if (NextWrite == -1)
{
NextWrite = Buffer.Length - 1;
}
Buffer[NextWrite--].Reset();
Count--;
}
NextWrite = 0;
NextPos = 0;
Count = 0;
}
// For assert:
private bool InBounds(int pos)
{
return pos < NextPos && pos >= NextPos - Count;
}
private int GetIndex(int pos)
{
int index = NextWrite - (NextPos - pos);
if (index < 0)
{
index += Buffer.Length;
}
return index;
}
/// <summary>
/// Get T instance for this absolute position;
/// this is allowed to be arbitrarily far "in the
/// future" but cannot be before the last freeBefore.
/// </summary>
public virtual T Get(int pos)
{
//System.out.println("RA.get pos=" + pos + " nextPos=" + nextPos + " nextWrite=" + nextWrite + " count=" + count);
while (pos >= NextPos)
{
if (Count == Buffer.Length)
{
var newBuffer = new T[ArrayUtil.Oversize(1 + Count, RamUsageEstimator.NUM_BYTES_OBJECT_REF)];
Array.Copy(Buffer, NextWrite, newBuffer, 0, Buffer.Length - NextWrite);
Array.Copy(Buffer, 0, newBuffer, Buffer.Length - NextWrite, NextWrite);
for (int i = Buffer.Length; i < newBuffer.Length; i++)
{
newBuffer[i] = NewInstance();
}
NextWrite = Buffer.Length;
Buffer = newBuffer;
}
if (NextWrite == Buffer.Length)
{
NextWrite = 0;
}
// Should have already been reset:
NextWrite++;
NextPos++;
Count++;
}
Debug.Assert(InBounds(pos));
int index = GetIndex(pos);
return Buffer[index];
}
/// <summary>
/// Returns the maximum position looked up, or -1 if no
/// position has been looked up sinc reset/init.
/// </summary>
public virtual int MaxPos
{
get
{
return NextPos - 1;
}
}
public virtual void FreeBefore(int pos)
{
int toFree = Count - (NextPos - pos);
Debug.Assert(toFree >= 0);
Debug.Assert(toFree <= Count, "toFree=" + toFree + " count=" + Count);
int index = NextWrite - Count;
if (index < 0)
{
index += Buffer.Length;
}
for (int i = 0; i < toFree; i++)
{
if (index == Buffer.Length)
{
index = 0;
}
//System.out.println(" fb idx=" + index);
Buffer[index].Reset();
index++;
}
Count -= toFree;
}
}
}