| using Lucene.Net.Codecs.Sep; |
| using Lucene.Net.Diagnostics; |
| using Lucene.Net.Store; |
| using System.Diagnostics; |
| |
| namespace Lucene.Net.Codecs.IntBlock |
| { |
| /* |
| * 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. |
| */ |
| |
| // TODO: much of this can be shared code w/ the fixed case |
| |
| /// <summary> |
| /// Abstract base class that writes variable-size blocks of ints |
| /// to an <see cref="IndexOutput"/>. While this is a simple approach, a |
| /// more performant approach would directly create an impl |
| /// of <see cref="Int32IndexOutput"/> inside <see cref="Directory"/>. Wrapping a generic |
| /// <see cref="IndexOutput"/> will likely cost performance. |
| /// <para/> |
| /// NOTE: This was VariableIntBlockIndexOutput in Lucene |
| /// <para/> |
| /// @lucene.experimental |
| /// </summary> |
| /// <remarks> |
| /// Naive int block API that writes vInts. This is |
| /// expected to give poor performance; it's really only for |
| /// testing the pluggability. One should typically use pfor instead. |
| /// </remarks> |
| public abstract class VariableInt32BlockIndexOutput : Int32IndexOutput |
| { |
| protected readonly IndexOutput m_output; |
| |
| private int upto; |
| private bool hitExcDuringWrite; |
| |
| // TODO what Var-Var codecs exist in practice... and what are there blocksizes like? |
| // if its less than 128 we should set that as max and use byte? |
| |
| /// <summary> |
| /// NOTE: <paramref name="maxBlockSize"/> must be the maximum block size |
| /// plus the max non-causal lookahead of your codec. EG Simple9 |
| /// requires lookahead=1 because on seeing the Nth value |
| /// it knows it must now encode the N-1 values before it. |
| /// </summary> |
| protected VariableInt32BlockIndexOutput(IndexOutput output, int maxBlockSize) |
| { |
| this.m_output = output; |
| this.m_output.WriteInt32(maxBlockSize); |
| } |
| |
| /// <summary> |
| /// Called one value at a time. Return the number of |
| /// buffered input values that have been written to out. |
| /// </summary> |
| protected abstract int Add(int value); |
| |
| public override Int32IndexOutput.Index GetIndex() |
| { |
| return new Index(this); |
| } |
| |
| new private class Index : Int32IndexOutput.Index |
| { |
| private readonly VariableInt32BlockIndexOutput outerInstance; |
| |
| public Index(VariableInt32BlockIndexOutput outerInstance) |
| { |
| this.outerInstance = outerInstance; |
| } |
| |
| private long fp; |
| private int upto; |
| private long lastFP; |
| private int lastUpto; |
| |
| public override void Mark() |
| { |
| fp = outerInstance.m_output.GetFilePointer(); |
| upto = outerInstance.upto; |
| } |
| |
| public override void CopyFrom(Int32IndexOutput.Index other, bool copyLast) |
| { |
| Index idx = (Index)other; |
| fp = idx.fp; |
| upto = idx.upto; |
| if (copyLast) |
| { |
| lastFP = fp; |
| lastUpto = upto; |
| } |
| } |
| |
| public override void Write(DataOutput indexOut, bool absolute) |
| { |
| if (Debugging.AssertsEnabled) Debugging.Assert(upto >= 0); |
| if (absolute) |
| { |
| indexOut.WriteVInt32(upto); |
| indexOut.WriteVInt64(fp); |
| } |
| else if (fp == lastFP) |
| { |
| // same block |
| if (Debugging.AssertsEnabled) Debugging.Assert(upto >= lastUpto); |
| int uptoDelta = upto - lastUpto; |
| indexOut.WriteVInt32(uptoDelta << 1 | 1); |
| } |
| else |
| { |
| // new block |
| indexOut.WriteVInt32(upto << 1); |
| indexOut.WriteVInt64(fp - lastFP); |
| } |
| lastUpto = upto; |
| lastFP = fp; |
| } |
| } |
| |
| public override void Write(int v) |
| { |
| hitExcDuringWrite = true; |
| upto -= Add(v) - 1; |
| hitExcDuringWrite = false; |
| if (Debugging.AssertsEnabled) Debugging.Assert(upto >= 0); |
| } |
| |
| protected override void Dispose(bool disposing) |
| { |
| if (disposing) |
| { |
| try |
| { |
| if (hitExcDuringWrite) return; |
| |
| // stuff 0s in until the "real" data is flushed: |
| var stuffed = 0; |
| while (upto > stuffed) |
| { |
| upto -= Add(0) - 1; |
| if (Debugging.AssertsEnabled) Debugging.Assert(upto >= 0); |
| stuffed += 1; |
| } |
| } |
| finally |
| { |
| m_output.Dispose(); |
| } |
| } |
| } |
| } |
| } |