blob: d4f47165bfbb333d9dd766523538fc30c99bd47a [file] [log] [blame]
using Lucene.Net.Documents;
using System;
using Lucene.Net.Diagnostics;
using System.Runtime.CompilerServices;
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 DocIdSetIterator = Lucene.Net.Search.DocIdSetIterator;
using FixedBitSet = Lucene.Net.Util.FixedBitSet;
using InPlaceMergeSorter = Lucene.Net.Util.InPlaceMergeSorter;
using NumericDocValuesUpdate = Lucene.Net.Index.DocValuesUpdate.NumericDocValuesUpdate;
using PackedInt32s = Lucene.Net.Util.Packed.PackedInt32s;
using PagedGrowableWriter = Lucene.Net.Util.Packed.PagedGrowableWriter;
using PagedMutable = Lucene.Net.Util.Packed.PagedMutable;
/// <summary>
/// A <see cref="DocValuesFieldUpdates"/> which holds updates of documents, of a single
/// <see cref="NumericDocValuesField"/>.
/// <para/>
/// @lucene.experimental
/// </summary>
internal class NumericDocValuesFieldUpdates : DocValuesFieldUpdates
{
new internal sealed class Iterator : DocValuesFieldUpdates.Iterator
{
private readonly int size;
private readonly PagedGrowableWriter values;
private readonly FixedBitSet docsWithField;
private readonly PagedMutable docs;
private long idx = 0; // long so we don't overflow if size == Integer.MAX_VALUE
private int doc = -1;
private long? value = null;
internal Iterator(int size, PagedGrowableWriter values, FixedBitSet docsWithField, PagedMutable docs)
{
this.size = size;
this.values = values;
this.docsWithField = docsWithField;
this.docs = docs;
}
public override object Value => value;
public override int NextDoc()
{
if (idx >= size)
{
value = null;
return doc = DocIdSetIterator.NO_MORE_DOCS;
}
doc = (int)docs.Get(idx);
++idx;
while (idx < size && docs.Get(idx) == doc)
{
++idx;
}
if (!docsWithField.Get((int)(idx - 1)))
{
value = null;
}
else
{
// idx points to the "next" element
value = values.Get(idx - 1);
}
return doc;
}
public override int Doc => doc;
public override void Reset()
{
doc = -1;
value = null;
idx = 0;
}
}
private FixedBitSet docsWithField;
private PagedMutable docs;
private PagedGrowableWriter values;
private int size;
public NumericDocValuesFieldUpdates(string field, int maxDoc)
: base(field, DocValuesFieldUpdatesType.NUMERIC)
{
docsWithField = new FixedBitSet(64);
docs = new PagedMutable(1, 1024, PackedInt32s.BitsRequired(maxDoc - 1), PackedInt32s.COMPACT);
values = new PagedGrowableWriter(1, 1024, 1, PackedInt32s.FAST);
size = 0;
}
public override void Add(int doc, object value)
{
// TODO: if the Sorter interface changes to take long indexes, we can remove that limitation
if (size == int.MaxValue)
{
throw new InvalidOperationException("cannot support more than System.Int32.MaxValue doc/value entries");
}
long? val = (long?)value;
if (val == null)
{
val = NumericDocValuesUpdate.MISSING;
}
// grow the structures to have room for more elements
if (docs.Count == size)
{
docs = docs.Grow(size + 1);
values = values.Grow(size + 1);
docsWithField = FixedBitSet.EnsureCapacity(docsWithField, (int)docs.Count);
}
if (val != NumericDocValuesUpdate.MISSING)
{
// only mark the document as having a value in that field if the value wasn't set to null (MISSING)
docsWithField.Set(size);
}
docs.Set(size, doc);
values.Set(size, (long)val);
++size;
}
public override DocValuesFieldUpdates.Iterator GetIterator()
{
PagedMutable docs = this.docs;
PagedGrowableWriter values = this.values;
FixedBitSet docsWithField = this.docsWithField;
new InPlaceMergeSorterAnonymousClass(docs, values, docsWithField).Sort(0, size);
return new Iterator(size, values, docsWithField, docs);
}
private class InPlaceMergeSorterAnonymousClass : InPlaceMergeSorter
{
private readonly PagedMutable docs;
private readonly PagedGrowableWriter values;
private readonly FixedBitSet docsWithField;
public InPlaceMergeSorterAnonymousClass(PagedMutable docs, PagedGrowableWriter values, FixedBitSet docsWithField)
{
this.docs = docs;
this.values = values;
this.docsWithField = docsWithField;
}
protected override void Swap(int i, int j)
{
long tmpDoc = docs.Get(j);
docs.Set(j, docs.Get(i));
docs.Set(i, tmpDoc);
long tmpVal = values.Get(j);
values.Set(j, values.Get(i));
values.Set(i, tmpVal);
bool tmpBool = docsWithField.Get(j);
if (docsWithField.Get(i))
{
docsWithField.Set(j);
}
else
{
docsWithField.Clear(j);
}
if (tmpBool)
{
docsWithField.Set(i);
}
else
{
docsWithField.Clear(i);
}
}
protected override int Compare(int i, int j)
{
int x = (int)docs.Get(i);
int y = (int)docs.Get(j);
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
public override void Merge(DocValuesFieldUpdates other)
{
if (Debugging.AssertsEnabled) Debugging.Assert(other is NumericDocValuesFieldUpdates);
NumericDocValuesFieldUpdates otherUpdates = (NumericDocValuesFieldUpdates)other;
if (size + otherUpdates.size > int.MaxValue)
{
throw new InvalidOperationException("cannot support more than System.Int32.MaxValue doc/value entries; size=" + size + " other.size=" + otherUpdates.size);
}
docs = docs.Grow(size + otherUpdates.size);
values = values.Grow(size + otherUpdates.size);
docsWithField = FixedBitSet.EnsureCapacity(docsWithField, (int)docs.Count);
for (int i = 0; i < otherUpdates.size; i++)
{
int doc = (int)otherUpdates.docs.Get(i);
if (otherUpdates.docsWithField.Get(i))
{
docsWithField.Set(size);
}
docs.Set(size, doc);
values.Set(size, otherUpdates.values.Get(i));
++size;
}
}
public override bool Any()
{
return size > 0;
}
}
}