Example #1
0
        /// <summary>
        /// Compares the current content of this writer with another one.
        /// </summary>
        /// <exception cref="InvalidOperationException">Content is not available, the builder has been linked with another one.</exception>
        public bool ContentEquals(BlobBuilder other)
        {
            if (!IsHead)
            {
                Throw.InvalidOperationBuilderAlreadyLinked();
            }

            if (ReferenceEquals(this, other))
            {
                return(true);
            }

            if (other == null)
            {
                return(false);
            }

            if (!other.IsHead)
            {
                Throw.InvalidOperationBuilderAlreadyLinked();
            }

            if (Count != other.Count)
            {
                return(false);
            }

            var leftEnumerator  = GetChunks();
            var rightEnumerator = other.GetChunks();
            int leftStart       = 0;
            int rightStart      = 0;

            bool leftContinues  = leftEnumerator.MoveNext();
            bool rightContinues = rightEnumerator.MoveNext();

            while (leftContinues && rightContinues)
            {
                Debug.Assert(leftStart == 0 || rightStart == 0);

                var left  = leftEnumerator.Current;
                var right = rightEnumerator.Current;

                int minLength = Math.Min(left.Length - leftStart, right.Length - rightStart);
                if (!ByteSequenceComparer.Equals(left._buffer, leftStart, right._buffer, rightStart, minLength))
                {
                    return(false);
                }

                leftStart  += minLength;
                rightStart += minLength;

                // nothing remains in left chunk to compare:
                if (leftStart == left.Length)
                {
                    leftContinues = leftEnumerator.MoveNext();
                    leftStart     = 0;
                }

                // nothing remains in left chunk to compare:
                if (rightStart == right.Length)
                {
                    rightContinues = rightEnumerator.MoveNext();
                    rightStart     = 0;
                }
            }

            return(leftContinues == rightContinues);
        }
Example #2
0
        /// <exception cref="ArgumentNullException"><paramref name="suffix"/> is null.</exception>
        /// <exception cref="InvalidOperationException">Builder is not writable, it has been linked with another one.</exception>
        public void LinkSuffix(BlobBuilder suffix)
        {
            if (suffix == null)
            {
                throw new ArgumentNullException(nameof(suffix));
            }

            // TODO: consider copying data from right to left while there is space

            if (!IsHead || !suffix.IsHead)
            {
                Throw.InvalidOperationBuilderAlreadyLinked();
            }

            // avoid chaining empty chunks:
            if (suffix.Count == 0)
            {
                return;
            }

            bool isEmpty = Count == 0;

            // swap buffers of the heads:
            var  suffixBuffer         = suffix._buffer;
            uint suffixLength         = suffix._length;
            int  suffixPreviousLength = suffix.PreviousLength;
            int  oldSuffixLength      = suffix.Length;

            suffix._buffer = _buffer;
            suffix._length = FrozenLength; // suffix is not a head anymore
            _buffer        = suffixBuffer;
            _length        = suffixLength;

            PreviousLength += suffix.Length + suffixPreviousLength;

            // Update the _previousLength of the suffix so that suffix.Count = suffix._previousLength + suffix.Length doesn't change.
            // Note that the resulting previous length might be negative.
            // The value is not used, other than for calculating the value of Count property.
            suffix._previousLengthOrFrozenSuffixLengthDelta = suffixPreviousLength + oldSuffixLength - suffix.Length;

            if (!isEmpty)
            {
                // First and last chunks:
                //
                // [First]->[]->[Last] <- [this]    [SuffixFirst]->[]->[SuffixLast]  <- [suffix]
                //    ^___________|                       ^_________________|
                //
                // Degenerate cases:
                // this == First == Last and/or suffix == SuffixFirst == SuffixLast.
                var first       = FirstChunk;
                var suffixFirst = suffix.FirstChunk;
                var last        = _nextOrPrevious;
                var suffixLast  = suffix._nextOrPrevious;

                // Relink like so:
                // [First]->[]->[Last] -> [suffix] -> [SuffixFirst]->[]->[SuffixLast]  <- [this]
                //    ^_______________________________________________________|
                _nextOrPrevious        = suffixLast;
                suffix._nextOrPrevious = (suffixFirst != suffix) ? suffixFirst : (first != this) ? first : suffix;

                if (last != this)
                {
                    last._nextOrPrevious = suffix;
                }

                if (suffixLast != suffix)
                {
                    suffixLast._nextOrPrevious = (first != this) ? first : suffix;
                }
            }

            CheckInvariants();
            suffix.CheckInvariants();
        }
Example #3
0
 // internal for testing
 internal void ClearChunk()
 {
     _length = 0;
     _previousLengthOrFrozenSuffixLengthDelta = 0;
     _nextOrPrevious = this;
 }