| /* |
| * |
| * 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.Util; |
| |
| namespace Lucene.Net.Support |
| { |
| /// <summary> |
| /// This class provides supporting methods of java.util.BitSet |
| /// that are not present in System.Collections.BitArray. |
| /// </summary> |
| internal static class BitArrayExtensions |
| { |
| /// <summary> |
| /// Returns the next set bit at or after index, or -1 if no such bit exists. |
| /// </summary> |
| /// <param name="bitArray"></param> |
| /// <param name="index">the index of bit array at which to start checking</param> |
| /// <returns>the next set bit or -1</returns> |
| public static int NextSetBit(this BitArray bitArray, int index) |
| { |
| while (index < bitArray.Length) |
| { |
| // if index bit is set, return it |
| // otherwise check next index bit |
| if (bitArray.Get(index)) |
| return index; |
| else |
| index++; |
| } |
| // if no bits are set at or after index, return -1 |
| return -1; |
| } |
| |
| public static int PrevSetBit(this BitArray bitArray, int index) |
| { |
| while (index >= 0 && index < bitArray.Length) |
| { |
| // if index bit is set, return it |
| // otherwise check previous index bit |
| if (bitArray.SafeGet(index)) |
| return index; |
| index--; |
| } |
| // if no bits are set at or before index, return -1 |
| return -1; |
| } |
| |
| // Produces a bitwise-and of the two BitArrays without requiring they be the same length |
| public static BitArray And_UnequalLengths(this BitArray bitsA, BitArray bitsB) |
| { |
| //Cycle only through fewest bits neccessary without requiring size equality |
| var maxIdx = Math.Min(bitsA.Length, bitsB.Length);//exclusive |
| var bits = new BitArray(maxIdx); |
| for (int i = 0; i < maxIdx; i++) |
| { |
| bits[i] = bitsA[i] & bitsB[i]; |
| } |
| return bits; |
| } |
| |
| // Produces a bitwise-or of the two BitArrays without requiring they be the same length |
| public static BitArray Or_UnequalLengths(this BitArray bitsA, BitArray bitsB) |
| { |
| var shorter = bitsA.Length < bitsB.Length ? bitsA : bitsB; |
| var longer = bitsA.Length >= bitsB.Length ? bitsA : bitsB; |
| var bits = new BitArray(longer.Length); |
| for (int i = 0; i < longer.Length; i++) |
| { |
| if (i >= shorter.Length) |
| { |
| bits[i] = longer[i]; |
| } |
| else |
| { |
| bits[i] = shorter[i] | longer[i]; |
| } |
| } |
| |
| return bits; |
| } |
| |
| // Produces a bitwise-xor of the two BitArrays without requiring they be the same length |
| public static BitArray Xor_UnequalLengths(this BitArray bitsA, BitArray bitsB) |
| { |
| var shorter = bitsA.Length < bitsB.Length ? bitsA : bitsB; |
| var longer = bitsA.Length >= bitsB.Length ? bitsA : bitsB; |
| var bits = new BitArray(longer.Length); |
| for (int i = 0; i < longer.Length; i++) |
| { |
| if (i >= shorter.Length) |
| { |
| bits[i] = longer[i]; |
| } |
| else |
| { |
| bits[i] = shorter[i] ^ longer[i]; |
| } |
| } |
| |
| return bits; |
| } |
| |
| /// <summary> |
| /// Returns the next un-set bit at or after index, or -1 if no such bit exists. |
| /// </summary> |
| /// <param name="bitArray"></param> |
| /// <param name="index">the index of bit array at which to start checking</param> |
| /// <returns>the next set bit or -1</returns> |
| public static int NextClearBit(this BitArray bitArray, int index) |
| { |
| while (index < bitArray.Length) |
| { |
| // if index bit is not set, return it |
| // otherwise check next index bit |
| if (!bitArray.Get(index)) |
| return index; |
| else |
| index++; |
| } |
| // if no bits are set at or after index, return -1 |
| return -1; |
| } |
| |
| /// <summary> |
| /// Returns the number of bits set to <c>true</c> in this <see cref="BitArray"/>. |
| /// </summary> |
| /// <param name="bits">This <see cref="BitArray"/>.</param> |
| /// <returns>The number of bits set to true in this <see cref="BitArray"/>.</returns> |
| public static int Cardinality(this BitArray bits) |
| { |
| if (bits == null) |
| throw new ArgumentNullException(nameof(bits)); |
| int count = 0; |
| |
| #if FEATURE_BITARRAY_COPYTO |
| int bitsLength = bits.Length; |
| int[] ints = new int[(bitsLength >> 5) + 1]; |
| int intsLength = ints.Length; |
| int c; |
| |
| bits.CopyTo(ints, 0); |
| |
| // fix for not truncated bits in last integer that may have been set to true with SetAll() |
| ints[intsLength - 1] &= ~(-1 << (bitsLength % 32)); |
| |
| for (int i = 0; i < intsLength; i++) |
| { |
| c = ints[i]; |
| |
| // magic (http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel) |
| unchecked |
| { |
| c -= (c >> 1) & 0x55555555; |
| c = (c & 0x33333333) + ((c >> 2) & 0x33333333); |
| c = ((c + (c >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; |
| } |
| |
| count += c; |
| } |
| #else |
| for (int i = 0; i < bits.Length; i++) |
| { |
| if (bits[i]) |
| count++; |
| } |
| #endif |
| return count; |
| } |
| |
| /// <summary> |
| /// Sets the bit at the given <paramref name="index"/> to true. |
| /// </summary> |
| /// <param name="bits">The BitArray object.</param> |
| /// <param name="index">The position to set to true.</param> |
| public static void Set(this BitArray bits, int index) |
| { |
| bits.SafeSet(index, true); |
| } |
| |
| /// <summary> |
| /// Sets the bit at the given index range to true. |
| /// </summary> |
| /// <param name="bits">The BitArray object.</param> |
| /// <param name="fromIndex">The start of the range to set(inclusive)</param> |
| /// <param name="toIndex">The end of the range to set(exclusive)</param> |
| /// <param name="value">the value to set to the range</param> |
| public static void Set(this BitArray bits, int fromIndex, int toIndex, bool value) |
| { |
| for (int i = fromIndex; i < toIndex; ++i) |
| { |
| bits.SafeSet(i, value); |
| } |
| } |
| |
| /// <summary> |
| /// Sets the bit at the given <paramref name="index"/> to false. |
| /// </summary> |
| /// <param name="bits">The BitArray object.</param> |
| /// <param name="index">The position to set to false.</param> |
| public static void Clear(this BitArray bits, int index) |
| { |
| bits.SafeSet(index, false); |
| } |
| |
| /// <summary> |
| /// Sets all bits to false |
| /// </summary> |
| /// <param name="bits">The BitArray object.</param> |
| public static void Clear(this BitArray bits) |
| { |
| bits.SetAll(false); |
| } |
| |
| //Flip all bits in the desired range, startIdx inclusive to endIdx exclusive |
| public static void Flip(this BitArray bits, int startIdx, int endIdx) |
| { |
| for (int i = startIdx; i < endIdx; i++) |
| { |
| bits[i] = !bits[i]; |
| } |
| } |
| |
| // Sets all bits in the range to false [startIdx, endIdx) |
| public static void Clear(this BitArray bits, int startIdx, int endIdx) |
| { |
| for (int i = startIdx; i < endIdx; i++) |
| { |
| bits[i] = false; |
| } |
| } |
| |
| // Sets all bits in the range to true [startIdx, endIdx) |
| public static void Set(this BitArray bits, int startIdx, int endIdx) |
| { |
| for (int i = startIdx; i < endIdx; i++) |
| { |
| bits[i] = true; |
| } |
| } |
| |
| // Emulates the Java BitSet.Get() method. |
| // Prevents exceptions from being thrown when the index is too high. |
| public static bool SafeGet(this BitArray a, int loc) |
| { |
| return loc < a.Length && a.Get(loc); |
| } |
| |
| //Emulates the Java BitSet.Set() method. Required to reconcile differences between Java BitSet and C# BitArray |
| public static void SafeSet(this BitArray a, int loc, bool value) |
| { |
| if (loc >= a.Length) |
| a.Length = loc + 1; |
| |
| a.Set(loc, value); |
| } |
| |
| // Clears all bits in this BitArray that correspond to a set bit in the parameter BitArray |
| public static void AndNot(this BitArray bitsA, BitArray bitsB) |
| { |
| //if (Debugging.AssertsEnabled) Debugging.Assert(bitsA.Length == bitsB.Length, "BitArray lengths are not the same"); |
| for (int i = 0; i < bitsA.Length; i++) |
| { |
| //bitsA was longer than bitsB |
| if (i >= bitsB.Length) |
| { |
| return; |
| } |
| if (bitsA[i] && bitsB[i]) |
| { |
| bitsA[i] = false; |
| } |
| } |
| } |
| |
| //Does a deep comparison of two BitArrays |
| public static bool BitWiseEquals(this BitArray bitsA, BitArray bitsB) |
| { |
| if (bitsA == bitsB) |
| return true; |
| if (bitsA.Length != bitsB.Length) |
| return false; |
| |
| for (int i = 0; i < bitsA.Length; i++) |
| { |
| if (bitsA[i] != bitsB[i]) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| //Compares a BitArray with an OpenBitSet |
| public static bool Equal(this BitArray a, OpenBitSet b) |
| { |
| var bitArrayCardinality = a.Cardinality(); |
| if (bitArrayCardinality != b.Cardinality()) |
| return false; |
| |
| for (int i = 0; i < bitArrayCardinality; i++) |
| { |
| if (a.SafeGet(i) != b.Get(i)) |
| return false; |
| } |
| |
| return true; |
| } |
| } |
| } |