public void TestSharedPrefix()
        {
            Assert.AreEqual(4, BufferUtils.SharedPrefixLength(
                                ByteBuffer.Wrap(b("abcdef")),
                                ByteBuffer.Wrap(b("abcd__"))));

            Assert.AreEqual(0, BufferUtils.SharedPrefixLength(
                                ByteBuffer.Wrap(b("")),
                                ByteBuffer.Wrap(b("_"))));

            Assert.AreEqual(2, BufferUtils.SharedPrefixLength(
                                ByteBuffer.Wrap(b("abcdef"), 2, 2),
                                ByteBuffer.Wrap(b("___cd__"), 3, 2)));

            //      Assertions.assertThat(
            //        BufferUtils.SharedPrefixLength(
            //            ByteBuffer.Wrap(b("abcdef")),
            //    ByteBuffer.Wrap(b("abcd__"))))
            //.isEqualTo(4);

            //Assertions.assertThat(
            //    BufferUtils.SharedPrefixLength(
            //        ByteBuffer.Wrap(b("")),
            //    ByteBuffer.Wrap(b("_"))))
            //.isEqualTo(0);

            //Assertions.assertThat(
            //    BufferUtils.SharedPrefixLength(
            //        ByteBuffer.Wrap(b("abcdef"), 2, 2),
            //    ByteBuffer.Wrap(b("___cd__"), 3, 2)))
            //.isEqualTo(2);
        }
        /// <summary>
        ///
        /// </summary>
        public virtual ByteBuffer Encode(ByteBuffer reuse, ByteBuffer source, ByteBuffer target)
        {
            int sharedPrefix  = BufferUtils.SharedPrefixLength(source, target);
            int truncateBytes = source.Remaining - sharedPrefix;

            if (truncateBytes >= RemoveEverything)
            {
                truncateBytes = RemoveEverything;
                sharedPrefix  = 0;
            }

            reuse = BufferUtils.ClearAndEnsureCapacity(reuse, 1 + target.Remaining - sharedPrefix);

            Debug.Assert(target.HasArray &&
                         target.Position == 0 &&
                         target.ArrayOffset == 0);

            byte suffixTrimCode = (byte)(truncateBytes + 'A');

            reuse.Put(suffixTrimCode)
            .Put(target.Array, sharedPrefix, target.Remaining - sharedPrefix)
            .Flip();

            return(reuse);
        }
        /// <summary>
        ///
        /// </summary>
        public virtual ByteBuffer Encode(ByteBuffer reuse, ByteBuffer source, ByteBuffer target)
        {
            // Search for the maximum matching subsequence that can be encoded.
            int maxSubsequenceLength = 0;
            int maxSubsequenceIndex  = 0;

            for (int i = 0; i < source.Remaining; i++)
            {
                // prefix at i => shared subsequence (infix)
                int sharedPrefix = BufferUtils.SharedPrefixLength(source, i, target, 0);
                // Only update maxSubsequenceLength if we will be able to encode it.
                if (sharedPrefix > maxSubsequenceLength && i < RemoveEverything &&
                    (source.Remaining - (i + sharedPrefix)) < RemoveEverything)
                {
                    maxSubsequenceLength = sharedPrefix;
                    maxSubsequenceIndex  = i;
                }
            }

            // Determine how much to remove (and where) from src to get a prefix of dst.
            int truncatePrefixBytes = maxSubsequenceIndex;
            int truncateSuffixBytes = (source.Remaining - (maxSubsequenceIndex + maxSubsequenceLength));

            if (truncatePrefixBytes >= RemoveEverything || truncateSuffixBytes >= RemoveEverything)
            {
                maxSubsequenceIndex = maxSubsequenceLength = 0;
                truncatePrefixBytes = truncateSuffixBytes = RemoveEverything;
            }

            int len1 = target.Remaining - maxSubsequenceLength;

            reuse = BufferUtils.ClearAndEnsureCapacity(reuse, 2 + len1);

            Debug.Assert(target.HasArray &&
                         target.Position == 0 &&
                         target.ArrayOffset == 0);

            reuse.Put((byte)((truncatePrefixBytes + 'A') & 0xFF));
            reuse.Put((byte)((truncateSuffixBytes + 'A') & 0xFF));
            reuse.Put(target.Array, maxSubsequenceLength, len1);
            reuse.Flip();

            return(reuse);
        }
Пример #4
0
        /// <summary>
        ///
        /// </summary>
        public virtual ByteBuffer Encode(ByteBuffer reuse, ByteBuffer source, ByteBuffer target)
        {
            Debug.Assert(source.HasArray &&
                         source.Position == 0 &&
                         source.ArrayOffset == 0);

            Debug.Assert(target.HasArray &&
                         target.Position == 0 &&
                         target.ArrayOffset == 0);

            // Search for the infix that can we can encode and remove from src
            // to get a maximum-length prefix of dst. This could be done more efficiently
            // by running a smarter longest-common-subsequence algorithm and some pruning (?).
            //
            // For now, naive loop should do.

            // There can be only two positions for the infix to delete:
            // 1) we remove leading bytes, even if they are partially matching (but a longer match
            //    exists somewhere later on).
            // 2) we leave max. matching prefix and remove non-matching bytes that follow.
            int maxInfixIndex        = 0;
            int maxSubsequenceLength = BufferUtils.SharedPrefixLength(source, target);
            int maxInfixLength       = 0;

            foreach (int i in new int[] { 0, maxSubsequenceLength })
            {
                for (int j = 1; j <= source.Remaining - i; j++)
                {
                    // Compute temporary src with the infix removed.
                    // Concatenate in scratch space for simplicity.
                    int len2 = source.Remaining - (i + j);
                    scratch = BufferUtils.ClearAndEnsureCapacity(scratch, i + len2);
                    scratch.Put(source.Array, 0, i);
                    scratch.Put(source.Array, i + j, len2);
                    scratch.Flip();

                    int sharedPrefix = BufferUtils.SharedPrefixLength(scratch, target);

                    // Only update maxSubsequenceLength if we will be able to encode it.
                    if (sharedPrefix > 0 && sharedPrefix > maxSubsequenceLength && i < RemoveEverything && j < RemoveEverything)
                    {
                        maxSubsequenceLength = sharedPrefix;
                        maxInfixIndex        = i;
                        maxInfixLength       = j;
                    }
                }
            }

            int truncateSuffixBytes = source.Remaining - (maxInfixLength + maxSubsequenceLength);

            // Special case: if we're removing the suffix in the infix code, move it
            // to the suffix code instead.
            if (truncateSuffixBytes == 0 &&
                maxInfixIndex + maxInfixLength == source.Remaining)
            {
                truncateSuffixBytes = maxInfixLength;
                maxInfixIndex       = maxInfixLength = 0;
            }

            if (maxInfixIndex >= RemoveEverything ||
                maxInfixLength >= RemoveEverything ||
                truncateSuffixBytes >= RemoveEverything)
            {
                maxInfixIndex  = maxSubsequenceLength = 0;
                maxInfixLength = truncateSuffixBytes = RemoveEverything;
            }

            int len1 = target.Remaining - maxSubsequenceLength;

            reuse = BufferUtils.ClearAndEnsureCapacity(reuse, 3 + len1);

            reuse.Put((byte)((maxInfixIndex + 'A') & 0xFF));
            reuse.Put((byte)((maxInfixLength + 'A') & 0xFF));
            reuse.Put((byte)((truncateSuffixBytes + 'A') & 0xFF));
            reuse.Put(target.Array, maxSubsequenceLength, len1);
            reuse.Flip();

            return(reuse);
        }