/// <summary>Flush the state and update the header</summary> /// <returns>Slice contained the finished compressed bitmap</returns> /// <remarks>You cannot write any more words after Packing, until <see cref="Reset"/> is called.</remarks> public void Pack() { if (m_packed) { ThrowAlreadyPacked(); } // flush any pending word Flush(); if (m_words == 0) { // empty! m_bounds = BitRange.Empty; // there will be no header m_writer.Position = m_head; } else { // we need to find the lowest and highest bits m_bounds = CompressedBitmap.ComputeBounds(m_writer.ToMutableSlice(), m_words); // update the header int p; m_writer.Rewind(out p, m_head); //the last word is either a literal, or a 1-bit filler m_writer.WriteFixed32(CompressedWord.MakeHeader(m_bounds.Highest)); m_writer.Position = p; } m_packed = true; }
public CompressedBitmapBuilder(CompressedBitmap bitmap) { if (bitmap == null) { throw new ArgumentNullException("bitmap"); } if ((bitmap.Data.Count & 3) != 0) { throw new ArgumentException("Bitmap's underlying buffer size should be a multiple of 4 bytes", "bitmap"); } if (bitmap.Count == 0) { m_words = s_emptyArray; var range = BitRange.Empty; m_lowest = range.Lowest; m_highest = range.Highest; } else { m_words = DecodeWords(bitmap.Data, bitmap.Count, bitmap.Bounds); m_size = bitmap.Count; var bounds = bitmap.Bounds; m_lowest = bounds.Lowest; m_highest = bounds.Highest; } }
public CompressedBitmapBitView(CompressedBitmap bitmap) { if (bitmap == null) { throw new ArgumentNullException("bitmap"); } m_bitmap = bitmap; }
/// <summary>Performs a logical NAND between two compressed bitmaps</summary> /// <param name="left">First compressed bitmap</param> /// <param name="right">Second compressed bitmap</param> /// <returns>Compressed slice with the result of boolean expression <paramref name="left"/> AND NOT(<paramref name="right"/>)</returns> public static CompressedBitmap AndNot(this CompressedBitmap left, CompressedBitmap right) { if (left == null) { throw new ArgumentNullException(nameof(left)); } if (right == null) { throw new ArgumentNullException(nameof(right)); } if (left.Count == 0 || right.Count == 0) { return(CompressedBitmap.Empty); } return(CompressedBinaryExpression(left, right, LogicalOperation.AndNot)); }
public static CompressedBitmap And([NotNull] this CompressedBitmap left, [NotNull] CompressedBitmap right) { if (left == null) { throw new ArgumentNullException("left"); } if (right == null) { throw new ArgumentNullException("right"); } if (left.Count == 0 || right.Count == 0) { return(CompressedBitmap.Empty); } return(CompressedBinaryExpression(left, right, LogicalOperation.And)); }
/// <summary>Returns a list of ids matching a specific value</summary> /// <param name="trans"></param> /// <param name="value">Value to lookup</param> /// <param name="reverse"></param> /// <returns>List of document ids matching this value for this particular index (can be empty if no document matches)</returns> public async Task <IEnumerable <long> > LookupAsync([NotNull] IFdbReadOnlyTransaction trans, TValue value, bool reverse = false) { var key = this.Location.Keys.Encode(value); var data = await trans.GetAsync(key).ConfigureAwait(false); if (data.IsNull) { return(null); } if (data.IsEmpty) { return(Enumerable.Empty <long>()); } var bitmap = new CompressedBitmap(data); if (reverse) { throw new NotImplementedException(); //TODO: GetView(reverse:true) ! } return(bitmap.GetView().Select(x => (long)x /*BUGBUG 64 bits*/)); }
public static CompressedBitmap XorNot([NotNull] this CompressedBitmap left, [NotNull] CompressedBitmap right) { if (left == null) { throw new ArgumentNullException(nameof(left)); } if (right == null) { throw new ArgumentNullException(nameof(right)); } if (left.Count == 0) { return(right.Count == 0 ? CompressedBitmap.Empty : right); } if (right.Count == 0) { return(left); } return(CompressedBinaryExpression(left, right, LogicalOperation.XorNot)); }
/// <summary>Performs a logical NOT on a compressed bitmaps</summary> /// <param name="bitmap">Compressed bitmap</param> /// <param name="size">Minimum logical size of the result (bits in the uncompressed bitmap)</param> /// <returns>Compressed slice with the result of flipping all the bits in <paramref name="bitmap"/>, containing up to at least <paramref name="size"/> bits.</returns> /// <remarks>If <paramref name="bitmap"/> is larger than <paramref name="size"/>, then the resulting bitmap will be larger.</remarks> public static CompressedBitmap Not(this CompressedBitmap bitmap, int size) { if (bitmap == null) { throw new ArgumentNullException(nameof(bitmap)); } // there is a high change that the final bitmap will have the same size, with an optional extra filler word at the end var writer = new CompressedBitmapWriter(bitmap.Count + 1); int n = 0; if (bitmap.Count > 0) { foreach (var word in bitmap) { if (word.IsLiteral) { writer.Write(CompressedWord.MakeLiteral((uint)(~word.Literal))); n += 31; } else { int fc = word.FillCount; writer.Write(word.FillBit == 1 ? CompressedWord.ALL_ZEROES : CompressedWord.ALL_ONES, fc); n += 31 * fc; } } } if (n < size) { writer.Write(CompressedWord.ALL_ONES, size / 31); int r = size % 31; if (r > 0) { writer.Write((1u << r) - 1); } } return(writer.GetBitmap()); }
/// <summary>Performs a binary operation between two compressed bitmaps</summary> /// <param name="left">First compressed bitmap</param> /// <param name="right">Second compressed bitmap</param> /// <param name="op">Type of operation to perform (And, Or, Xor, ...)</param> /// <returns>Compressed slice with the result of boolean expression <paramref name="left"/> AND <paramref name="right"/></returns> internal static CompressedBitmap CompressedBinaryExpression(CompressedBitmap left, CompressedBitmap right, LogicalOperation op) { Contract.Requires(left != null && right != null && /*op != LogicalOperation.And &&*/ Enum.IsDefined(typeof(LogicalOperation), op)); var writer = new CompressedBitmapWriter(); using (var liter = left.GetEnumerator()) using (var riter = right.GetEnumerator()) { int ln = 0; // remaining count of current word in left int rn = 0; // remaining count of current word in right uint lw = 0; // value of current word in left (if ln > 0) uint rw = 0; // value of current word in right (if rn > 0) const int DONE = -1; while (true) { if (ln == 0) { if (!liter.MoveNext()) { // left is done if (op == LogicalOperation.And || rn == DONE) { // no need to continue break; } // continue with right until it's done ln = DONE; lw = 0; continue; } ln = liter.Current.WordCount; lw = liter.Current.WordValue; } if (rn == 0) { if (!riter.MoveNext()) { // right is done if (op == LogicalOperation.And || ln == DONE) { // no need to continue break; } // continue with left until it's done rn = DONE; rw = 0; continue; } rn = riter.Current.WordCount; rw = riter.Current.WordValue; } if (ln == DONE) { // copy right writer.Write((uint)rw, rn); rn = 0; } else if (rn == DONE) { // copy left writer.Write((uint)lw, ln); ln = 0; } else { // merge left & right int n = Math.Min(ln, rn); switch (op) { case LogicalOperation.And: writer.Write((uint)(lw & rw), n); break; case LogicalOperation.AndNot: writer.Write((uint)(lw & (~rw & LITERAL_MASK)), n); break; case LogicalOperation.Or: writer.Write((uint)(lw | rw), n); break; case LogicalOperation.OrNot: writer.Write((uint)(lw | (~rw & LITERAL_MASK)), n); break; case LogicalOperation.Xor: writer.Write((uint)(lw ^ rw), n); break; case LogicalOperation.XorNot: writer.Write((uint)(lw ^ (~rw & LITERAL_MASK)), n); break; default: throw new InvalidOperationException(); } ln -= n; rn -= n; } } } return(writer.GetBitmap()); }
public CompressedBitmapBitView(CompressedBitmap bitmap) { Contract.NotNull(bitmap); m_bitmap = bitmap; }