blob: 3685f7c6ae91fa4843db1f69e4a821ec991432ea [file] [log] [blame]
using Lucene.Net.Support;
using System.Collections.Generic;
using System;
using System.Text;
using System.Collections;
namespace Lucene.Net.Search.Spans
{
/*
* 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 ToStringUtils = Lucene.Net.Util.ToStringUtils;
/// <summary>
/// Only return those matches that have a specific payload at
/// the given position.
/// <para/>
/// Do not use this with a <see cref="SpanQuery"/> that contains a <see cref="Lucene.Net.Search.Spans.SpanNearQuery"/>. Instead, use
/// <see cref="SpanNearPayloadCheckQuery"/> since it properly handles the fact that payloads
/// aren't ordered by <see cref="Lucene.Net.Search.Spans.SpanNearQuery"/>.
/// </summary>
public class SpanPayloadCheckQuery : SpanPositionCheckQuery
{
protected readonly ICollection<byte[]> m_payloadToMatch;
private readonly IEqualityComparer payloadEqualityComparer;
///
/// <param name="match"> The underlying <see cref="SpanQuery"/> to check </param>
/// <param name="payloadToMatch"> The <see cref="T:ICollection{byte[]}"/> of payloads to match.
/// IMPORTANT: If the type provided does not implement <see cref="IList{T}"/> (including arrays) or
/// <see cref="ISet{T}"/>, it should either implement <see cref="IStructuralEquatable"/> or override
/// <see cref="object.Equals(object)"/> and <see cref="object.GetHashCode()"/> with implementations
/// that compare the values of the byte arrays to ensure they are the same.</param>
public SpanPayloadCheckQuery(SpanQuery match, ICollection<byte[]> payloadToMatch)
: base(match)
{
if (match is SpanNearQuery)
{
throw new ArgumentException("SpanNearQuery not allowed");
}
this.m_payloadToMatch = payloadToMatch;
// LUCENENET specific: Need to use a structural equality comparer based on the type that is passed in.
if (payloadToMatch is ISet<byte[]>)
payloadEqualityComparer = J2N.Collections.Generic.SetEqualityComparer<byte[]>.Default;
else if (payloadToMatch is IList<byte[]>)
payloadEqualityComparer = J2N.Collections.Generic.ListEqualityComparer<byte[]>.Default;
else
payloadEqualityComparer = J2N.Collections.StructuralEqualityComparer.Default;
}
protected override AcceptStatus AcceptPosition(Spans spans)
{
bool result = spans.IsPayloadAvailable;
if (result == true)
{
var candidate = spans.GetPayload();
if (candidate.Count == m_payloadToMatch.Count)
{
//TODO: check the byte arrays are the same
using (var toMatchIter = m_payloadToMatch.GetEnumerator())
{
//check each of the byte arrays, in order
//hmm, can't rely on order here
foreach (var candBytes in candidate)
{
toMatchIter.MoveNext();
//if one is a mismatch, then return false
if (Arrays.Equals(candBytes, toMatchIter.Current) == false)
{
return AcceptStatus.NO;
}
}
}
//we've verified all the bytes
return AcceptStatus.YES;
}
else
{
return AcceptStatus.NO;
}
}
return AcceptStatus.YES;
}
public override string ToString(string field)
{
StringBuilder buffer = new StringBuilder();
buffer.Append("spanPayCheck(");
buffer.Append(m_match.ToString(field));
buffer.Append(", payloadRef: ");
foreach (var bytes in m_payloadToMatch)
{
ToStringUtils.ByteArray(buffer, bytes);
buffer.Append(';');
}
buffer.Append(")");
buffer.Append(ToStringUtils.Boost(Boost));
return buffer.ToString();
}
public override object Clone()
{
SpanPayloadCheckQuery result = new SpanPayloadCheckQuery((SpanQuery)m_match.Clone(), m_payloadToMatch);
result.Boost = Boost;
return result;
}
public override bool Equals(object o)
{
if (this == o)
{
return true;
}
if (!(o is SpanPayloadCheckQuery))
{
return false;
}
SpanPayloadCheckQuery other = (SpanPayloadCheckQuery)o;
// LUCENENET NOTE: Need to use the structural equality comparer to compare equality of all contained values
return payloadEqualityComparer.Equals(this.m_payloadToMatch, other.m_payloadToMatch)
&& this.m_match.Equals(other.m_match)
&& this.Boost == other.Boost;
}
public override int GetHashCode()
{
int h = m_match.GetHashCode();
h ^= (h << 8) | ((int)((uint)h >> 25)); // reversible
//TODO: is this right?
h ^= payloadEqualityComparer.GetHashCode(m_payloadToMatch); // LUCENENET NOTE: Need to use the structural equality comparer to compare equality of all contained values
h ^= J2N.BitConversion.SingleToRawInt32Bits(Boost);
return h;
}
}
}