private void WriteFiller(uint word, int count)
        {
            Contract.Requires(count > 0);

            uint previous = m_current;

            if (previous == word)
            {             // continuation of current run
                m_counter += count;
                return;
            }

            if (previous == NO_VALUE)
            {             // start of new run
                m_counter += count;
                m_current  = word;
                return;
            }

            // switch from one type to the other
            m_words += m_counter;
            if (previous == CompressedWord.ALL_ZEROES)
            {
                m_writer.WriteFixed32(CompressedWord.MakeZeroes(m_counter));
            }
            else
            {
                m_writer.WriteFixed32(CompressedWord.MakeOnes(m_counter));
            }
            m_counter = count;
        }
        /// <summary>Flush the curernt state of the writer</summary>
        /// <remarks>Writing after calling flush may break filler sequences into chunks, and reduce the efficiency of the compression.
        /// It should only be called if you need to split a bitmap streaming into physical chunks (sending on a socket, writing to disk, ...)
        /// </remarks>
        public void Flush()
        {
            if (m_packed)
            {
                ThrowAlreadyPacked();
            }

            // either previous was a literal, or a run of zeroes or ones.
            Contract.Requires(m_counter == 0 ? (m_current == NO_VALUE) : (m_current == CompressedWord.ALL_ZEROES || m_current == CompressedWord.ALL_ONES));

            int counter = m_counter;

            if (counter > 0 && m_current == CompressedWord.ALL_ONES)
            {             // complete the last run only if it was all 1's
                m_writer.WriteFixed32(CompressedWord.MakeOnes(counter));
                m_words += counter;
            }
            m_counter = 0;
            m_current = NO_VALUE;
        }
        private void WriteLiteral(uint word, int count)
        {
            Contract.Requires(count > 0);

            uint previous = m_current;
            int  counter  = m_counter;

            // finish whatever was left open previously
            if (previous != NO_VALUE)
            {             // need to close previous filler
                Contract.Assert(counter > 0);
                if (previous == CompressedWord.ALL_ZEROES)
                {
                    m_writer.WriteFixed32(CompressedWord.MakeZeroes(counter));
                }
                else if (previous == CompressedWord.ALL_ONES)
                {
                    m_writer.WriteFixed32(CompressedWord.MakeOnes(counter));
                }
                else
                {
                    Contract.Assert(counter == 1);
                    m_writer.WriteFixed32(CompressedWord.MakeLiteral(previous));
                }
                m_words += counter;
            }

            // output the current literal
            int  n = count;
            uint w = CompressedWord.MakeLiteral(word);

            while (n-- > 0)
            {
                m_writer.WriteFixed32(w);
            }
            m_words  += count;
            m_current = NO_VALUE;
            m_counter = 0;
        }
예제 #4
0
        /// <summary>Set a bit in the bitmap.</summary>
        /// <param name="index">Absolute index (0-based) of the bit to set</param>
        /// <returns>True if the bit was changed from 0 to 1; or false if it was already set.</returns>
        public bool Set(int index)
        {
            if (index < 0)
            {
                throw new ArgumentException("Bit index cannot be less than zero.", "index");
            }

            //Console.WriteLine("Set({0}) on {1}-words bitmap", index, m_size);

            if (index > m_highest)
            {
                m_highest = index;
            }
            if (index < m_lowest)
            {
                m_lowest = index;
            }

            uint mask;
            int  wordIndex = GetWordIndex(index, out mask);
            //Console.WriteLine("> bitOffset {0} is in data word #{1} with mask {2}", index, wordIndex, mask);

            int offset, position, count;

            if (!GetCompressedWordIndex(wordIndex, out offset, out position))
            {             // falls outside the bitmap, need to add new words
                count = wordIndex - position;
                if (count > 0)
                {
                    //Console.WriteLine("> outside by {0}, need filler", count);
                    EnsureCapacity(m_size + 2);
                    m_words[m_size++] = CompressedWord.MakeZeroes(count);
                }
                else
                {
                    //Console.WriteLine("> outside, right next to it");
                    EnsureCapacity(m_size + 1);
                }
                m_words[m_size++] = CompressedWord.MakeLiteral(mask);
                return(true);
            }

            //Console.WriteLine("> would be in slot #{0} which starts at data-word #{1}", offset, position);

            // read the existing word
            var word = m_words[offset];

            // we can patch literals in place
            if (word.IsLiteral)
            {
                //Console.WriteLine("> PATCH [...] [{0}:0x{0:X8}] [...]", offset, mask);
                var before = word.RawValue;
                var after  = before | mask;
                if (before == after)
                {
                    return(false);
                }

                if (after == CompressedWord.ALL_ONES)
                {                 // convert to an all 1 literal!
                    if (offset > 0)
                    {
                        // check if we can merge with a previous 1-filler
                        var prev = m_words[offset - 1];
                        if (!prev.IsLiteral && prev.FillBit == 1)
                        {
                            m_words[offset - 1] = CompressedWord.MakeOnes(prev.FillCount + 1);
                            int r = m_size - offset - 1;
                            if (r > 0)
                            {
                                Array.Copy(m_words, offset + 1, m_words, offset, r);
                            }
                            --m_size;
                            return(true);
                        }
                    }
                    //TODO: also need to check if the next one is also a filler!

                    // convert this one to a filler
                    after = CompressedWord.MakeOnes(1);
                }
                m_words[offset] = new CompressedWord(after);
                return(true);
            }

            // if it an all-1 filler, our job is already done
            if (word.FillBit == 1)
            {
                //Console.WriteLine("> was already a 1-filler");
                return(false);
            }

            // for all-1 fillers, we must break them so that we can insert a new literal
            SplitFiller(word, offset, mask, wordIndex - position);
            return(true);
        }