blob: e3bffd4ee8d5eb9227192849b39a580adf565500 [file] [log] [blame]
using System.Collections.Generic;
using System.Diagnostics;
namespace Lucene.Net.Index
{
using AttributeSource = Lucene.Net.Util.AttributeSource;
using Bits = Lucene.Net.Util.Bits;
/*
* 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;
/// <summary>
/// Abstract class for enumerating a subset of all terms.
///
/// <p>Term enumerations are always ordered by
/// <seealso cref="#getComparator"/>. Each term in the enumeration is
/// greater than all that precede it.</p>
/// <p><em>Please note:</em> Consumers of this enum cannot
/// call {@code seek()}, it is forward only; it throws
/// <seealso cref="UnsupportedOperationException"/> when a seeking method
/// is called.
/// </summary>
public abstract class FilteredTermsEnum : TermsEnum
{
private BytesRef InitialSeekTerm_Renamed = null;
private bool DoSeek;
private BytesRef ActualTerm = null;
private readonly TermsEnum Tenum;
/// <summary>
/// Return value, if term should be accepted or the iteration should
/// {@code END}. The {@code *_SEEK} values denote, that after handling the current term
/// the enum should call <seealso cref="#nextSeekTerm"/> and step forward. </summary>
/// <seealso cref= #accept(BytesRef) </seealso>
protected internal enum AcceptStatus
{
/// <summary>
/// Accept the term and position the enum at the next term. </summary>
YES,
/// <summary>
/// Accept the term and advance (<seealso cref="FilteredTermsEnum#nextSeekTerm(BytesRef)"/>)
/// to the next term.
/// </summary>
YES_AND_SEEK,
/// <summary>
/// Reject the term and position the enum at the next term. </summary>
NO,
/// <summary>
/// Reject the term and advance (<seealso cref="FilteredTermsEnum#nextSeekTerm(BytesRef)"/>)
/// to the next term.
/// </summary>
NO_AND_SEEK,
/// <summary>
/// Reject the term and stop enumerating. </summary>
END
}
/// <summary>
/// Return if term is accepted, not accepted or the iteration should ended
/// (and possibly seek).
/// </summary>
protected internal abstract AcceptStatus Accept(BytesRef term);
/// <summary>
/// Creates a filtered <seealso cref="TermsEnum"/> on a terms enum. </summary>
/// <param name="tenum"> the terms enumeration to filter. </param>
public FilteredTermsEnum(TermsEnum tenum)
: this(tenum, true)
{
}
/// <summary>
/// Creates a filtered <seealso cref="TermsEnum"/> on a terms enum. </summary>
/// <param name="tenum"> the terms enumeration to filter. </param>
public FilteredTermsEnum(TermsEnum tenum, bool startWithSeek)
{
Debug.Assert(tenum != null);
this.Tenum = tenum;
DoSeek = startWithSeek;
}
/// <summary>
/// Use this method to set the initial <seealso cref="BytesRef"/>
/// to seek before iterating. this is a convenience method for
/// subclasses that do not override <seealso cref="#nextSeekTerm"/>.
/// If the initial seek term is {@code null} (default),
/// the enum is empty.
/// <P>You can only use this method, if you keep the default
/// implementation of <seealso cref="#nextSeekTerm"/>.
/// </summary>
protected internal BytesRef InitialSeekTerm
{
set
{
this.InitialSeekTerm_Renamed = value;
}
}
/// <summary>
/// On the first call to <seealso cref="#next"/> or if <seealso cref="#accept"/> returns
/// <seealso cref="AcceptStatus#YES_AND_SEEK"/> or <seealso cref="AcceptStatus#NO_AND_SEEK"/>,
/// this method will be called to eventually seek the underlying TermsEnum
/// to a new position.
/// On the first call, {@code currentTerm} will be {@code null}, later
/// calls will provide the term the underlying enum is positioned at.
/// this method returns per default only one time the initial seek term
/// and then {@code null}, so no repositioning is ever done.
/// <p>Override this method, if you want a more sophisticated TermsEnum,
/// that repositions the iterator during enumeration.
/// If this method always returns {@code null} the enum is empty.
/// <p><em>Please note:</em> this method should always provide a greater term
/// than the last enumerated term, else the behaviour of this enum
/// violates the contract for TermsEnums.
/// </summary>
protected internal virtual BytesRef NextSeekTerm(BytesRef currentTerm)
{
BytesRef t = InitialSeekTerm_Renamed;
InitialSeekTerm_Renamed = null;
return t;
}
/// <summary>
/// Returns the related attributes, the returned <seealso cref="AttributeSource"/>
/// is shared with the delegate {@code TermsEnum}.
/// </summary>
public override AttributeSource Attributes()
{
return Tenum.Attributes();
}
public override BytesRef Term()
{
return Tenum.Term();
}
public override IComparer<BytesRef> Comparator
{
get
{
return Tenum.Comparator;
}
}
public override int DocFreq()
{
return Tenum.DocFreq();
}
public override long TotalTermFreq()
{
return Tenum.TotalTermFreq();
}
/// <summary>
/// this enum does not support seeking! </summary>
/// <exception cref="UnsupportedOperationException"> In general, subclasses do not
/// support seeking. </exception>
public override bool SeekExact(BytesRef term)
{
throw new System.NotSupportedException(this.GetType().Name + " does not support seeking");
}
/// <summary>
/// this enum does not support seeking! </summary>
/// <exception cref="UnsupportedOperationException"> In general, subclasses do not
/// support seeking. </exception>
public override SeekStatus SeekCeil(BytesRef term)
{
throw new System.NotSupportedException(this.GetType().Name + " does not support seeking");
}
/// <summary>
/// this enum does not support seeking! </summary>
/// <exception cref="UnsupportedOperationException"> In general, subclasses do not
/// support seeking. </exception>
public override void SeekExact(long ord)
{
throw new System.NotSupportedException(this.GetType().Name + " does not support seeking");
}
public override long Ord()
{
return Tenum.Ord();
}
public override DocsEnum Docs(Bits bits, DocsEnum reuse, int flags)
{
return Tenum.Docs(bits, reuse, flags);
}
public override DocsAndPositionsEnum DocsAndPositions(Bits bits, DocsAndPositionsEnum reuse, int flags)
{
return Tenum.DocsAndPositions(bits, reuse, flags);
}
/// <summary>
/// this enum does not support seeking! </summary>
/// <exception cref="UnsupportedOperationException"> In general, subclasses do not
/// support seeking. </exception>
public override void SeekExact(BytesRef term, TermState state)
{
throw new System.NotSupportedException(this.GetType().Name + " does not support seeking");
}
/// <summary>
/// Returns the filtered enums term state
/// </summary>
public override TermState TermState()
{
Debug.Assert(Tenum != null);
return Tenum.TermState();
}
public override BytesRef Next()
{
//System.out.println("FTE.next doSeek=" + doSeek);
//new Throwable().printStackTrace(System.out);
for (; ; )
{
// Seek or forward the iterator
if (DoSeek)
{
DoSeek = false;
BytesRef t = NextSeekTerm(ActualTerm);
//System.out.println(" seek to t=" + (t == null ? "null" : t.utf8ToString()) + " tenum=" + tenum);
// Make sure we always seek forward:
Debug.Assert(ActualTerm == null || t == null || Comparator.Compare(t, ActualTerm) > 0, "curTerm=" + ActualTerm + " seekTerm=" + t);
if (t == null || Tenum.SeekCeil(t) == SeekStatus.END)
{
// no more terms to seek to or enum exhausted
//System.out.println(" return null");
return null;
}
ActualTerm = Tenum.Term();
//System.out.println(" got term=" + actualTerm.utf8ToString());
}
else
{
ActualTerm = Tenum.Next();
if (ActualTerm == null)
{
// enum exhausted
return null;
}
}
// check if term is accepted
switch (Accept(ActualTerm))
{
case FilteredTermsEnum.AcceptStatus.YES_AND_SEEK:
DoSeek = true;
// term accepted, but we need to seek so fall-through
goto case FilteredTermsEnum.AcceptStatus.YES;
case FilteredTermsEnum.AcceptStatus.YES:
// term accepted
return ActualTerm;
case FilteredTermsEnum.AcceptStatus.NO_AND_SEEK:
// invalid term, seek next time
DoSeek = true;
break;
case FilteredTermsEnum.AcceptStatus.END:
// we are supposed to end the enum
return null;
}
}
}
}
}