/*
* 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 System;
using System.Collections;
using Lucene.Net.Search;
using Lucene.Net.Util;
namespace Lucene.Net.Spatial.Util
{
/* BitSet of fixed length (numBits), backed by accessible
* ({@link #getBits}) long[], accessed with an int index,
* implementing Bits and DocIdSet. Unlike {@link
* OpenBitSet} this bit set does not auto-expand, cannot
* handle long index, and does not have fastXX/XX variants
* (just X).
*
* @lucene.internal
**/
public class FixedBitSet : DocIdSet, IBits
{
private readonly BitArray bits;
///
/// returns the number of 64 bit words it would take to hold numBits
///
///
///
public static int bits2words(int numBits)
{
var numLong = (int)((uint)numBits >> 6);
if ((numBits & 63) != 0)
{
numLong++;
}
return numLong;
}
public FixedBitSet(int numBits)
{
bits = new BitArray(numBits);
}
///
/// Makes full copy.
///
///
public FixedBitSet(FixedBitSet other)
{
bits = new BitArray(other.bits);
}
public IBits Bits()
{
return this;
}
public int Length()
{
return bits.Length;
}
public override bool IsCacheable
{
get { return true; }
}
///
/// Returns number of set bits. NOTE: this visits every
/// long in the backing bits array, and the result is not
/// internally cached!
///
///
public int Cardinality()
{
int ret = 0;
for (var i = 0; i < bits.Length; i++)
{
if (bits[i]) ret++;
}
return ret;
}
public bool Get(int index)
{
return bits[index];
}
public void Set(int index)
{
bits.Set(index, true);
}
public bool GetAndSet(int index)
{
var ret = bits[index];
bits.Set(index, true);
return ret;
}
public void Clear(int index)
{
bits.Set(index, false);
}
public bool GetAndClear(int index)
{
var ret = bits[index];
bits.Set(index, false);
return ret;
}
///
/// Returns the index of the first set bit starting at the index specified.
/// -1 is returned if there are no more set bits.
///
///
///
public int NextSetBit(int index)
{
if (index >= bits.Length || index < 0)
throw new ArgumentException("Invalid index", "index");
for (var i = index; i < bits.Length; i++)
{
if (bits[i]) return i;
}
return -1;
}
/* Returns the index of the last set bit before or on the index specified.
* -1 is returned if there are no more set bits.
*/
public int PrevSetBit(int index)
{
if (index >= bits.Length || index < 0)
throw new ArgumentException("Invalid index", "index");
for (var i = index; i >= 0; i--)
{
if (bits[i]) return i;
}
return -1;
}
/* Does in-place OR of the bits provided by the
* iterator. */
//public void Or(DocIdSetIterator iter)
//{
// if (iter is OpenBitSetIterator && iter.DocID() == -1)
// {
// var obs = (OpenBitSetIterator)iter;
// Or(obs.arr, obs.words);
// // advance after last doc that would be accepted if standard
// // iteration is used (to exhaust it):
// obs.Advance(bits.Length);
// }
// else
// {
// int doc;
// while ((doc = iter.NextDoc()) < bits.Length)
// {
// Set(doc);
// }
// }
//}
/* this = this OR other */
public void Or(FixedBitSet other)
{
Or(other.bits, other.bits.Length);
}
private void Or(BitArray otherArr, int otherLen)
{
var thisArr = this.bits;
int pos = Math.Min(thisArr.Length, otherLen);
while (--pos >= 0)
{
thisArr[pos] |= otherArr[pos];
}
}
/* Does in-place AND of the bits provided by the
* iterator. */
//public void And(DocIdSetIterator iter)
//{
// if (iter is OpenBitSetIterator && iter.DocID() == -1)
// {
// var obs = (OpenBitSetIterator)iter;
// And(obs.arr, obs.words);
// // advance after last doc that would be accepted if standard
// // iteration is used (to exhaust it):
// obs.Advance(bits.Length);
// }
// else
// {
// if (bits.Length == 0) return;
// int disiDoc, bitSetDoc = NextSetBit(0);
// while (bitSetDoc != -1 && (disiDoc = iter.Advance(bitSetDoc)) < bits.Length)
// {
// Clear(bitSetDoc, disiDoc);
// disiDoc++;
// bitSetDoc = (disiDoc < bits.Length) ? NextSetBit(disiDoc) : -1;
// }
// if (bitSetDoc != -1)
// {
// Clear(bitSetDoc, bits.Length);
// }
// }
//}
/* this = this AND other */
public void And(FixedBitSet other)
{
And(other.bits, other.bits.Length);
}
private void And(BitArray otherArr, int otherLen)
{
var thisArr = this.bits;
int pos = Math.Min(thisArr.Length, otherLen);
while (--pos >= 0)
{
thisArr[pos] &= otherArr[pos];
}
if (thisArr.Length > otherLen)
{
for (var i = otherLen; i < thisArr.Length; i++)
{
thisArr[i] = false;
}
}
}
/* Does in-place AND NOT of the bits provided by the
* iterator. */
//public void AndNot(DocIdSetIterator iter)
//{
// var obs = iter as OpenBitSetIterator;
// if (obs != null && iter.DocID() == -1)
// {
// AndNot(obs.arr, obs.words);
// // advance after last doc that would be accepted if standard
// // iteration is used (to exhaust it):
// obs.Advance(bits.Length);
// }
// else
// {
// int doc;
// while ((doc = iter.NextDoc()) < bits.Length)
// {
// Clear(doc);
// }
// }
//}
/* this = this AND NOT other */
public void AndNot(FixedBitSet other)
{
AndNot(other.bits, other.bits.Length);
}
private void AndNot(BitArray otherArr, int otherLen)
{
var thisArr = this.bits;
int pos = Math.Min(thisArr.Length, otherLen);
while (--pos >= 0)
{
thisArr[pos] &= !otherArr[pos];
}
}
// NOTE: no .isEmpty() here because that's trappy (ie,
// typically isEmpty is low cost, but this one wouldn't
// be)
/* Flips a range of bits
*
* @param startIndex lower index
* @param endIndex one-past the last bit to flip
*/
// public void Flip(int startIndex, int endIndex) {
// Debug.Assert(startIndex >= 0 && startIndex < numBits);
// Debug.Assert(endIndex >= 0 && endIndex <= numBits);
// if (endIndex <= startIndex) {
// return;
// }
// int startWord = startIndex >> 6;
// int endWord = (endIndex-1) >> 6;
// /* Grrr, java shifting wraps around so -1L>>>64 == -1
// * for that reason, make sure not to use endmask if the bits to flip will
// * be zero in the last word (redefine endWord to be the last changed...)
// long startmask = -1L << (startIndex & 0x3f); // example: 11111...111000
// long endmask = -1L >>> (64-(endIndex & 0x3f)); // example: 00111...111111
// ***/
// long startmask = -1L << startIndex;
// long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex due to wrap
// if (startWord == endWord) {
// bits[startWord] ^= (startmask & endmask);
// return;
// }
// bits[startWord] ^= startmask;
// for (var i=startWord+1; i= 0 && startIndex < numBits);
// Debug.Assert(endIndex >= 0 && endIndex <= numBits);
// if (endIndex <= startIndex) {
// return;
// }
// int startWord = startIndex >> 6;
// int endWord = (endIndex-1) >> 6;
// long startmask = -1L << startIndex;
// long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex due to wrap
// if (startWord == endWord) {
// bits[startWord] |= (startmask & endmask);
// return;
// }
// bits[startWord] |= startmask;
// Arrays.Fill(bits, startWord+1, endWord, -1L);
// bits[endWord] |= endmask;
//}
/* Clears a range of bits.
*
* @param startIndex lower index
* @param endIndex one-past the last bit to clear
*/
public void Clear(int startIndex, int endIndex)
{
for (int i = startIndex; i < endIndex; i++)
{
Clear(i);
}
}
//@Override
public FixedBitSet Clone()
{
return new FixedBitSet(this);
}
/* returns true if both sets have the same bits set */
public override bool Equals(Object o)
{
if (this == o)
{
return true;
}
var other = o as FixedBitSet;
if (other == null)
{
return false;
}
return bits.Equals(other.bits);
}
public override int GetHashCode()
{
return bits.GetHashCode();
}
public override DocIdSetIterator Iterator()
{
return new FixedBitSetIterator(this);
}
///
/// A FixedBitSet Iterator implementation
///
public class FixedBitSetIterator : DocIdSetIterator
{
private int curDocId = -1;
private readonly IEnumerator enumerator;
public FixedBitSetIterator(FixedBitSet bitset)
{
enumerator = bitset.bits.GetEnumerator();
}
public override int DocID()
{
return curDocId;
}
public override int NextDoc()
{
while (enumerator.MoveNext())
{
++curDocId;
if ((bool)enumerator.Current) return curDocId;
}
return curDocId = NO_MORE_DOCS;
}
public override int Advance(int target)
{
int doc;
while ((doc = NextDoc()) < target)
{
}
return doc;
}
}
}
}