| using J2N.Numerics; |
| using Lucene.Net.Diagnostics; |
| using System; |
| using System.Collections; |
| using System.Collections.Generic; |
| using System.IO; |
| |
| namespace Lucene.Net.Index |
| { |
| /* |
| * 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 BytesRef = Lucene.Net.Util.BytesRef; |
| using IndexInput = Lucene.Net.Store.IndexInput; |
| using RAMFile = Lucene.Net.Store.RAMFile; |
| using RAMInputStream = Lucene.Net.Store.RAMInputStream; |
| using RAMOutputStream = Lucene.Net.Store.RAMOutputStream; |
| |
| /// <summary> |
| /// Prefix codes term instances (prefixes are shared) |
| /// <para/> |
| /// @lucene.experimental |
| /// </summary> |
| internal class PrefixCodedTerms : IEnumerable<Term> |
| { |
| internal readonly RAMFile buffer; |
| |
| private PrefixCodedTerms(RAMFile buffer) |
| { |
| this.buffer = buffer; |
| } |
| |
| /// <returns> size in bytes </returns> |
| public virtual long GetSizeInBytes() |
| { |
| return buffer.GetSizeInBytes(); |
| } |
| |
| /// <returns> iterator over the bytes </returns> |
| public virtual IEnumerator<Term> GetEnumerator() |
| { |
| return new PrefixCodedTermsIterator(buffer); |
| } |
| |
| IEnumerator IEnumerable.GetEnumerator() |
| { |
| return GetEnumerator(); |
| } |
| |
| internal class PrefixCodedTermsIterator : IEnumerator<Term> |
| { |
| private readonly IndexInput input; |
| private string field = ""; |
| private readonly BytesRef bytes = new BytesRef(); // LUCENENET: marked readonly |
| private readonly Term term; // LUCENENET: marked readonly |
| |
| internal PrefixCodedTermsIterator(RAMFile buffer) |
| { |
| term = new Term(field, bytes); |
| |
| try |
| { |
| input = new RAMInputStream("PrefixCodedTermsIterator", buffer); |
| } |
| catch (IOException e) |
| { |
| throw new Exception(e.ToString(), e); |
| } |
| } |
| |
| public virtual Term Current => term; |
| |
| public void Dispose() |
| { |
| Dispose(true); |
| GC.SuppressFinalize(true); |
| } |
| |
| protected virtual void Dispose(bool disposing) |
| { |
| if (disposing) |
| { |
| input?.Dispose(); // LUCENENET specific - call dispose on input |
| } |
| } |
| |
| object IEnumerator.Current => Current; |
| |
| public virtual bool MoveNext() |
| { |
| // LUCENENET specific - Since there is no way to check for a next element |
| // without calling this method in .NET, the assert is redundant and ineffective. |
| //if (Debugging.AssertsEnabled) Debugging.Assert(input.GetFilePointer() < input.Length); // Has next |
| if (input.GetFilePointer() < input.Length) |
| { |
| try |
| { |
| int code = input.ReadVInt32(); |
| if ((code & 1) != 0) |
| { |
| field = input.ReadString(); |
| } |
| int prefix = code.TripleShift(1); |
| int suffix = input.ReadVInt32(); |
| bytes.Grow(prefix + suffix); |
| input.ReadBytes(bytes.Bytes, prefix, suffix); |
| bytes.Length = prefix + suffix; |
| term.Set(field, bytes); |
| } |
| catch (IOException e) |
| { |
| throw new Exception(e.ToString(), e); |
| } |
| |
| return true; |
| } |
| return false; |
| } |
| |
| public virtual void Reset() |
| { |
| throw new NotSupportedException(); |
| } |
| } |
| |
| /// <summary> |
| /// Builds a <see cref="PrefixCodedTerms"/>: call add repeatedly, then finish. </summary> |
| public class Builder |
| { |
| public Builder() |
| { |
| output = new RAMOutputStream(buffer); |
| } |
| |
| private readonly RAMFile buffer = new RAMFile(); // LUCENENET: marked readonly |
| private readonly RAMOutputStream output; // LUCENENET: marked readonly |
| private readonly Term lastTerm = new Term(""); // LUCENENET: marked readonly |
| |
| /// <summary> |
| /// add a term </summary> |
| public virtual void Add(Term term) |
| { |
| if (Debugging.AssertsEnabled) Debugging.Assert(lastTerm.Equals(new Term("")) || term.CompareTo(lastTerm) > 0); |
| |
| try |
| { |
| int prefix = SharedPrefix(lastTerm.Bytes, term.Bytes); |
| int suffix = term.Bytes.Length - prefix; |
| if (term.Field.Equals(lastTerm.Field, StringComparison.Ordinal)) |
| { |
| output.WriteVInt32(prefix << 1); |
| } |
| else |
| { |
| output.WriteVInt32(prefix << 1 | 1); |
| output.WriteString(term.Field); |
| } |
| output.WriteVInt32(suffix); |
| output.WriteBytes(term.Bytes.Bytes, term.Bytes.Offset + prefix, suffix); |
| lastTerm.Bytes.CopyBytes(term.Bytes); |
| lastTerm.Field = term.Field; |
| } |
| catch (IOException e) |
| { |
| throw new Exception(e.ToString(), e); |
| } |
| } |
| |
| /// <returns> |
| /// finalized form </returns> |
| public virtual PrefixCodedTerms Finish() |
| { |
| try |
| { |
| output.Dispose(); |
| return new PrefixCodedTerms(buffer); |
| } |
| catch (IOException e) |
| { |
| throw new Exception(e.ToString(), e); |
| } |
| } |
| |
| private int SharedPrefix(BytesRef term1, BytesRef term2) |
| { |
| int pos1 = 0; |
| int pos1End = pos1 + Math.Min(term1.Length, term2.Length); |
| int pos2 = 0; |
| while (pos1 < pos1End) |
| { |
| if (term1.Bytes[term1.Offset + pos1] != term2.Bytes[term2.Offset + pos2]) |
| { |
| return pos1; |
| } |
| pos1++; |
| pos2++; |
| } |
| return pos1; |
| } |
| } |
| } |
| } |