blob: 167667818dc654003241ab2a441bd9592c1bd698 [file] [log] [blame]
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Lucene.Net.Index
{
using Lucene.Net.Support;
using System.IO;
using BytesRef = Lucene.Net.Util.BytesRef;
/*
* 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 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)
/// @lucene.experimental
/// </summary>
public class PrefixCodedTerms : IEnumerable<Term>
{
internal readonly RAMFile Buffer;
private PrefixCodedTerms(RAMFile buffer)
{
this.Buffer = buffer;
}
/// <returns> size in bytes </returns>
public virtual long SizeInBytes
{
get
{
return Buffer.SizeInBytes;
}
}
/// <returns> iterator over the bytes </returns>
public virtual IEnumerator<Term> GetEnumerator()
{
return new PrefixCodedTermsIterator(Buffer);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
internal class PrefixCodedTermsIterator : IEnumerator<Term>
{
private readonly IndexInput input;
private string field = "";
private BytesRef bytes = new BytesRef();
private Term term;
public PrefixCodedTermsIterator(RAMFile buffer)
{
term = new Term(field, bytes);
try
{
input = new RAMInputStream("PrefixCodedTermsIterator", buffer);
}
catch (System.IO.IOException)
{
throw;
}
}
public Term Current
{
get { return term; }
}
public void Dispose()
{
}
object System.Collections.IEnumerator.Current
{
get { return Current; }
}
public bool MoveNext()
{
if (input.FilePointer < input.Length())
{
int code = input.ReadVInt();
if ((code & 1) != 0)
{
field = input.ReadString();
}
int prefix = Number.URShift(code, 1);
int suffix = input.ReadVInt();
bytes.Grow(prefix + suffix);
input.ReadBytes(bytes.Bytes, prefix, suffix);
bytes.Length = prefix + suffix;
term.Set(field, bytes);
return true;
}
return false;
}
public void Reset()
{
throw new NotImplementedException();
}
}
/// <summary>
/// Builds a PrefixCodedTerms: call add repeatedly, then finish. </summary>
public class Builder
{
internal bool InstanceFieldsInitialized = false;
public Builder()
{
if (!InstanceFieldsInitialized)
{
InitializeInstanceFields();
InstanceFieldsInitialized = true;
}
}
internal virtual void InitializeInstanceFields()
{
Output = new RAMOutputStream(Buffer);
}
internal RAMFile Buffer = new RAMFile();
internal RAMOutputStream Output;
internal Term LastTerm = new Term("");
/// <summary>
/// add a term </summary>
public virtual void Add(Term term)
{
Debug.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))
{
Output.WriteVInt(prefix << 1);
}
else
{
Output.WriteVInt(prefix << 1 | 1);
Output.WriteString(term.Field);
}
Output.WriteVInt(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.Message, e);
}
}
/// <summary>
/// return finalized form </summary>
public virtual PrefixCodedTerms Finish()
{
try
{
Output.Dispose();
return new PrefixCodedTerms(Buffer);
}
catch (IOException e)
{
throw new Exception(e.Message, e);
}
}
internal virtual 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;
}
}
}
}