Esempio n. 1
0
        public void Append(ReadIterator begin, ReadIterator end)
        {
            var clonedBegin = MemoryBlockSegment.Clone(begin, end);
            var clonedEnd   = clonedBegin;

            while (clonedEnd.Next != null)
            {
                clonedEnd = clonedEnd.Next;
            }

            if (_tail == null)
            {
                _head      = clonedBegin;
                _headIndex = clonedBegin.Start;
            }
            else
            {
                Debug.Assert(_tail.Block != null);
                Debug.Assert(_tail.Next == null);
                Debug.Assert(_tail.End == _tailIndex);

                _tail.Next = clonedBegin;
            }

            _tail      = clonedEnd;
            _tailIndex = clonedEnd.End;
        }
Esempio n. 2
0
        internal void Append(WritableBuffer buffer)
        {
            lock (_sync)
            {
                if (Interlocked.CompareExchange(ref _producingState, 0, 1) != 1)
                {
                    throw new InvalidOperationException("No ongoing producing operation to complete.");
                }

                if (buffer.IsDefault)
                {
                    // REVIEW: Should we signal the completion?
                    return;
                }

                if (_head == null)
                {
                    // Update the head to point to the head of the buffer. This
                    // happens if we called alloc(0) then write
                    _head       = buffer.Head;
                    _head.Start = buffer.HeadIndex;
                }
                // If buffer.Head == tail it means we appended data to the tail
                else if (_tail != null && buffer.Head != _tail)
                {
                    // If we have a tail point next to the head of the buffer
                    Volatile.Write(ref _tail.Next, buffer.Head);
                }

                // Always update tail to the buffer's tail
                _tail     = buffer.Tail;
                _tail.End = buffer.TailIndex;
            }
        }
Esempio n. 3
0
        public static MemoryBlockSegment Clone(ReadIterator beginBuffer, ReadIterator endBuffer)
        {
            var beginOrig = beginBuffer.Segment;
            var endOrig   = endBuffer.Segment;

            if (beginOrig == endOrig)
            {
                return(new MemoryBlockSegment(beginOrig.Block, beginBuffer.Index, endBuffer.Index));
            }

            var beginClone = new MemoryBlockSegment(beginOrig.Block, beginBuffer.Index, beginOrig.End);
            var endClone   = beginClone;

            beginOrig = beginOrig.Next;

            while (beginOrig != endOrig)
            {
                endClone.Next = new MemoryBlockSegment(beginOrig.Block, beginOrig.Start, beginOrig.End);

                endClone  = endClone.Next;
                beginOrig = beginOrig.Next;
            }

            endClone.Next = new MemoryBlockSegment(endOrig.Block, endOrig.Start, endBuffer.Index);

            return(beginClone);
        }
Esempio n. 4
0
        public static MemoryBlockSegment Clone(ReadCursor beginBuffer, ReadCursor endBuffer, out MemoryBlockSegment lastBlockSegment)
        {
            var beginOrig = beginBuffer.Segment;
            var endOrig   = endBuffer.Segment;

            if (beginOrig == endOrig)
            {
                lastBlockSegment = new MemoryBlockSegment(beginOrig.Block, beginBuffer.Index, endBuffer.Index);
                return(lastBlockSegment);
            }

            var beginClone = new MemoryBlockSegment(beginOrig.Block, beginBuffer.Index, beginOrig.End);
            var endClone   = beginClone;

            beginOrig = beginOrig.Next;

            while (beginOrig != endOrig)
            {
                endClone.Next = new MemoryBlockSegment(beginOrig.Block, beginOrig.Start, beginOrig.End);

                endClone  = endClone.Next;
                beginOrig = beginOrig.Next;
            }

            lastBlockSegment = new MemoryBlockSegment(endOrig.Block, endOrig.Start, endBuffer.Index);
            endClone.Next    = lastBlockSegment;

            return(beginClone);
        }
Esempio n. 5
0
        /// <summary>
        /// Save the data at the current location then move to the next available space.
        /// </summary>
        /// <param name="data">The byte to be saved.</param>
        /// <returns>true if the operation successes. false if can't find available space.</returns>
        internal bool Put(byte data)
        {
            if (_segment == null)
            {
                return(false);
            }

            var segment = _segment;
            var index   = _index;

            while (true)
            {
                var wasLastBlock = segment.Next == null;

                if (index < segment.End)
                {
                    _segment = segment;
                    _index   = index + 1;
                    segment.Block.Array[index] = data;
                    return(true);
                }
                else if (wasLastBlock)
                {
                    return(false);
                }
                else
                {
                    segment = segment.Next;
                    index   = segment.Start;
                }
            }
        }
Esempio n. 6
0
        internal int CopyTo(byte[] array, int offset, int count)
        {
            if (IsDefault)
            {
                return(0);
            }

            var actual    = 0;
            var segment   = _segment;
            var index     = _index;
            var remaining = count;

            while (true)
            {
                // Determine if we might attempt to copy data from segment.Next before
                // calculating "following" so we don't risk skipping data that could
                // be added after segment.End when we decide to copy from segment.Next.
                // segment.End will always be advanced before segment.Next is set.
                var wasLastBlock = segment.Next == null;
                var following    = segment.End - index;
                if (remaining <= following)
                {
                    actual = count;
                    if (array != null)
                    {
                        Buffer.BlockCopy(segment.Block.Array, index, array, offset, remaining);
                    }

                    _segment = segment;
                    _index   = index + remaining;
                    return(actual);
                }
                else if (wasLastBlock)
                {
                    actual = count - remaining + following;
                    if (array != null)
                    {
                        Buffer.BlockCopy(segment.Block.Array, index, array, offset, following);
                    }
                    _segment = segment;
                    _index   = following;
                    return(actual);
                }
                else
                {
                    if (array != null)
                    {
                        Buffer.BlockCopy(segment.Block.Array, index, array, offset, following);
                    }
                    offset    += following;
                    remaining -= following;
                    segment    = segment.Next;
                    index      = segment.Start;
                }
            }
        }
Esempio n. 7
0
        internal WritableBuffer(MemoryPool pool, MemoryBlockSegment segment)
        {
            _pool = pool;

            _tail      = segment;
            _tailIndex = segment?.End ?? 0;

            _head      = segment;
            _headIndex = _tailIndex;
        }
Esempio n. 8
0
        internal bool TryGetBuffer(ReadCursor end, out BufferSpan span)
        {
            span = default(BufferSpan);

            if (IsDefault)
            {
                return(false);
            }

            var segment = _segment;
            var index   = _index;

            // Determine if we might attempt to copy data from segment.Next before
            // calculating "following" so we don't risk skipping data that could
            // be added after segment.End when we decide to copy from segment.Next.
            // segment.End will always be advanced before segment.Next is set.

            int following = 0;

            while (true)
            {
                var wasLastBlock = segment.Next == null || end.Segment == segment;

                if (end.Segment == segment)
                {
                    following = end.Index - index;
                }
                else
                {
                    following = segment.End - index;
                }

                if (following > 0)
                {
                    break;
                }

                if (wasLastBlock)
                {
                    return(false);
                }
                else
                {
                    segment = segment.Next;
                    index   = segment.Start;
                }
            }

            span = new BufferSpan(segment, index, following);

            _segment = segment;
            _index   = index + following;
            return(true);
        }
Esempio n. 9
0
        public void Write(byte[] data, int offset, int count)
        {
            if (_tail == null)
            {
                _tail      = new MemoryBlockSegment(_pool.Lease());
                _tailIndex = _tail.End;
                _head      = _tail;
                _headIndex = _tail.Start;
            }

            Debug.Assert(_tail.Block != null);
            Debug.Assert(_tail.Next == null);
            Debug.Assert(_tail.End == _tailIndex);

            var segment          = _tail;
            var block            = _tail.Block;
            var blockIndex       = _tailIndex;
            var bufferIndex      = offset;
            var remaining        = count;
            var bytesLeftInBlock = block.Data.Offset + block.Data.Count - blockIndex;

            while (remaining > 0)
            {
                // Try the block empty if the segment is reaodnly
                if (bytesLeftInBlock == 0 || segment.ReadOnly)
                {
                    var nextBlock   = _pool.Lease();
                    var nextSegment = new MemoryBlockSegment(nextBlock);
                    segment.End = blockIndex;
                    Volatile.Write(ref segment.Next, nextSegment);
                    segment = nextSegment;
                    block   = nextBlock;

                    blockIndex       = block.Data.Offset;
                    bytesLeftInBlock = block.Data.Count;
                }

                var bytesToCopy = remaining < bytesLeftInBlock ? remaining : bytesLeftInBlock;

                Buffer.BlockCopy(data, bufferIndex, block.Array, blockIndex, bytesToCopy);

                blockIndex       += bytesToCopy;
                bufferIndex      += bytesToCopy;
                remaining        -= bytesToCopy;
                bytesLeftInBlock -= bytesToCopy;
            }

            segment.End   = blockIndex;
            segment.Block = block;
            _tail         = segment;
            _tailIndex    = blockIndex;
        }
Esempio n. 10
0
        internal WritableBuffer(Channel channel, MemoryPool pool, MemoryBlockSegment segment)
        {
            _channel = channel;
            _pool    = pool;

            _tail      = segment;
            _tailIndex = segment?.End ?? 0;

            _head      = segment;
            _headIndex = _tailIndex;

            _comitted = false;
        }
Esempio n. 11
0
        internal int Seek(int bytes)
        {
            if (_segment == null || IsEnd)
            {
                return(0);
            }

            var wasLastBlock = _segment.Next == null;
            var following    = _segment.End - _index;

            if (following >= bytes)
            {
                _index += bytes;
                return(bytes);
            }

            var segment = _segment;
            var index   = _index;

            while (true)
            {
                if (wasLastBlock)
                {
                    _segment = segment;
                    _index   = index + following;
                    return(following);
                }
                else
                {
                    bytes  -= following;
                    segment = segment.Next;
                    index   = segment.Start;
                }

                wasLastBlock = segment.Next == null;
                following    = segment.End - index;

                if (following >= bytes)
                {
                    _segment = segment;
                    _index   = index + bytes;
                    return(bytes);
                }
            }
        }
Esempio n. 12
0
        public ReadableBuffer Clone()
        {
            var begin = _start;
            var end   = _end;

            var segmentHead = MemoryBlockSegment.Clone(begin, end);
            var segmentTail = segmentHead;

            while (segmentTail.Next != null)
            {
                segmentTail = segmentTail.Next;
            }

            begin = new ReadIterator(segmentHead);
            end   = new ReadIterator(segmentTail, segmentTail.End);

            return(new ReadableBuffer(begin, end, isOwner: true));
        }
Esempio n. 13
0
        internal void Skip(int bytesToSkip)
        {
            if (_segment == null)
            {
                return;
            }

            var wasLastBlock = _segment.Next == null;
            var following    = _segment.End - _index;

            if (following >= bytesToSkip)
            {
                _index += bytesToSkip;
                return;
            }

            var segment = _segment;
            var index   = _index;

            while (true)
            {
                if (wasLastBlock)
                {
                    throw new InvalidOperationException("Attempted to skip more bytes than available.");
                }
                else
                {
                    bytesToSkip -= following;
                    segment      = segment.Next;
                    index        = segment.Start;
                }

                wasLastBlock = segment.Next == null;
                following    = segment.End - index;

                if (following >= bytesToSkip)
                {
                    _segment = segment;
                    _index   = index + bytesToSkip;
                    return;
                }
            }
        }
Esempio n. 14
0
        public WritableBuffer Alloc(int minimumSize = 0)
        {
            if (Interlocked.CompareExchange(ref _producingState, 1, 0) != 0)
            {
                throw new InvalidOperationException("Already producing.");
            }

            MemoryBlockSegment segment = null;

            if (_tail != null && !_tail.ReadOnly)
            {
                // Try to return the tail so the calling code can append to it
                int remaining = _tail.Block.Data.Offset + _tail.Block.Data.Count - _tail.End;

                if (minimumSize <= remaining)
                {
                    segment = _tail;
                }
            }

            if (segment == null && minimumSize > 0)
            {
                // We're out of tail space so lease a new segment only if the requested size > 0
                segment = new MemoryBlockSegment(_pool.Lease());
            }

            lock (_sync)
            {
                if (_head == null)
                {
                    _head = segment;
                }
                else if (segment != null && segment != _tail)
                {
                    // Append the segment to the tail if it's non-null
                    Volatile.Write(ref _tail.Next, segment);
                    _tail = segment;
                }

                return(new WritableBuffer(this, _pool, segment));
            }
        }
Esempio n. 15
0
        private ReadableBuffer(ref ReadableBuffer buffer)
        {
            _channel = buffer._channel;

            var begin = buffer._start;
            var end   = buffer._end;

            MemoryBlockSegment segmentTail;
            var segmentHead = MemoryBlockSegment.Clone(begin, end, out segmentTail);

            begin = new ReadCursor(segmentHead);
            end   = new ReadCursor(segmentTail, segmentTail.End);

            _start   = begin;
            _end     = end;
            _isOwner = true;
            _span    = buffer._span;

            _length = buffer._length;
        }
Esempio n. 16
0
        public void EndRead(
            ReadCursor consumed,
            ReadCursor examined)
        {
            MemoryBlockSegment returnStart = null;
            MemoryBlockSegment returnEnd   = null;

            lock (_sync)
            {
                if (!consumed.IsDefault)
                {
                    returnStart = _head;
                    returnEnd   = consumed.Segment;
                    _head       = consumed.Segment;
                    _head.Start = consumed.Index;
                }

                if (!examined.IsDefault &&
                    examined.IsEnd &&
                    Completion.Status == TaskStatus.WaitingForActivation)
                {
                    Interlocked.CompareExchange(
                        ref _awaitableState,
                        _awaitableIsNotCompleted,
                        _awaitableIsCompleted);
                }
            }

            while (returnStart != returnEnd)
            {
                var returnSegment = returnStart;
                returnStart = returnStart.Next;
                returnSegment.Dispose();
            }

            if (Interlocked.CompareExchange(ref _consumingState, 0, 1) != 1)
            {
                throw new InvalidOperationException("No ongoing consuming operation to complete.");
            }
        }
Esempio n. 17
0
        internal int Take()
        {
            var segment = _segment;

            if (segment == null)
            {
                return(-1);
            }

            var index        = _index;
            var wasLastBlock = segment.Next == null;

            if (index < segment.End)
            {
                _index = index + 1;
                return(segment.Block.Array[index]);
            }

            do
            {
                if (wasLastBlock)
                {
                    return(-1);
                }
                else
                {
                    segment = segment.Next;
                    index   = segment.Start;
                }

                wasLastBlock = segment.Next == null;

                if (index < segment.End)
                {
                    _segment = segment;
                    _index   = index + 1;
                    return(segment.Block.Array[index]);
                }
            } while (true);
        }
Esempio n. 18
0
        public void Append(ref ReadableBuffer buffer)
        {
            MemoryBlockSegment clonedEnd;
            var clonedBegin = MemoryBlockSegment.Clone(buffer.Start, buffer.End, out clonedEnd);

            if (_tail == null)
            {
                _head      = clonedBegin;
                _headIndex = clonedBegin.Start;
            }
            else
            {
                Debug.Assert(_tail.Block != null);
                Debug.Assert(_tail.Next == null);
                Debug.Assert(_tail.End == _tailIndex);

                _tail.Next = clonedBegin;
            }

            _tail      = clonedEnd;
            _tailIndex = clonedEnd.End;
        }
Esempio n. 19
0
        public void Ensure(int count)
        {
            if (_tail == null)
            {
                _tail      = new MemoryBlockSegment(_pool.Lease());
                _tailIndex = _tail.End;
                _head      = _tail;
                _headIndex = _tail.Start;
            }

            Debug.Assert(_tail.Block != null);
            Debug.Assert(_tail.Next == null);
            Debug.Assert(_tail.End == _tailIndex);

            var segment          = _tail;
            var block            = _tail.Block;
            var blockIndex       = _tailIndex;
            var remaining        = count;
            var bytesLeftInBlock = block.Data.Offset + block.Data.Count - blockIndex;

            // If inadequate bytes left or if the segment is readonly
            if (bytesLeftInBlock < count || segment.ReadOnly)
            {
                var nextBlock   = _pool.Lease();
                var nextSegment = new MemoryBlockSegment(nextBlock);
                segment.End = blockIndex;
                Volatile.Write(ref segment.Next, nextSegment);
                segment = nextSegment;
                block   = nextBlock;

                blockIndex = block.Data.Offset;

                segment.End   = blockIndex;
                segment.Block = block;
                _tail         = segment;
                _tailIndex    = blockIndex;
            }
        }
Esempio n. 20
0
        public void Dispose()
        {
            Debug.Assert(_completedWriting, "Not completed writing");
            Debug.Assert(_completedReading, "Not completed reading");

            lock (_sync)
            {
                // Return all segments
                var segment = _head;
                while (segment != null)
                {
                    var returnSegment = segment;
                    segment = segment.Next;

                    returnSegment.Dispose();
                }

                _head = null;
                _tail = null;

                Interlocked.Exchange(ref _disposeCallback, null)?.Invoke();
            }
        }
Esempio n. 21
0
        private void Dispose()
        {
            Debug.Assert(_completedWriting, "Not completed writing");
            Debug.Assert(_completedReading, "Not completed reading");

            lock (_sync)
            {
                // Return all segments
                var segment = _head;
                while (segment != null)
                {
                    var returnSegment = segment;
                    segment = segment.Next;

                    returnSegment.Dispose();
                }

                _head = null;
                _tail = null;

                _disposedTcs.TrySetResult(null);
            }
        }
Esempio n. 22
0
 internal BufferSpan(MemoryBlockSegment segment, int offset, int count)
 {
     _segment = segment;
     _length  = count;
     _offset  = offset;
 }
Esempio n. 23
0
 internal ReadCursor(MemoryBlockSegment segment)
 {
     _segment = segment;
     _index   = segment?.Start ?? 0;
 }
Esempio n. 24
0
 internal ReadCursor(MemoryBlockSegment segment, int index)
 {
     _segment = segment;
     _index   = index;
 }
Esempio n. 25
0
        internal unsafe int Seek(ref Vector <byte> byte0Vector, ref Vector <byte> byte1Vector, ref Vector <byte> byte2Vector)
        {
            if (IsDefault)
            {
                return(-1);
            }

            var segment      = _segment;
            var index        = _index;
            var wasLastBlock = segment.Next == null;
            var following    = segment.End - index;

            byte[] array;
            int    byte0Index = int.MaxValue;
            int    byte1Index = int.MaxValue;
            int    byte2Index = int.MaxValue;
            var    byte0      = byte0Vector[0];
            var    byte1      = byte1Vector[0];
            var    byte2      = byte2Vector[0];

            while (true)
            {
                while (following == 0)
                {
                    if (wasLastBlock)
                    {
                        _segment = segment;
                        _index   = index;
                        return(-1);
                    }
                    segment      = segment.Next;
                    index        = segment.Start;
                    wasLastBlock = segment.Next == null;
                    following    = segment.End - index;
                }
                array = segment.Block.Array;
                while (following > 0)
                {
                    // Need unit tests to test Vector path
#if !DEBUG
                    // Check will be Jitted away https://github.com/dotnet/coreclr/issues/1079
                    if (Vector.IsHardwareAccelerated)
                    {
#endif
                    if (following >= _vectorSpan)
                    {
                        var data        = new Vector <byte>(array, index);
                        var byte0Equals = Vector.Equals(data, byte0Vector);
                        var byte1Equals = Vector.Equals(data, byte1Vector);
                        var byte2Equals = Vector.Equals(data, byte2Vector);

                        if (!byte0Equals.Equals(Vector <byte> .Zero))
                        {
                            byte0Index = FindFirstEqualByte(ref byte0Equals);
                        }
                        if (!byte1Equals.Equals(Vector <byte> .Zero))
                        {
                            byte1Index = FindFirstEqualByte(ref byte1Equals);
                        }
                        if (!byte2Equals.Equals(Vector <byte> .Zero))
                        {
                            byte2Index = FindFirstEqualByte(ref byte2Equals);
                        }

                        if (byte0Index == int.MaxValue && byte1Index == int.MaxValue && byte2Index == int.MaxValue)
                        {
                            following -= _vectorSpan;
                            index     += _vectorSpan;
                            continue;
                        }

                        _segment = segment;

                        int toReturn, toMove;
                        if (byte0Index < byte1Index)
                        {
                            if (byte0Index < byte2Index)
                            {
                                toReturn = byte0;
                                toMove   = byte0Index;
                            }
                            else
                            {
                                toReturn = byte2;
                                toMove   = byte2Index;
                            }
                        }
                        else
                        {
                            if (byte1Index < byte2Index)
                            {
                                toReturn = byte1;
                                toMove   = byte1Index;
                            }
                            else
                            {
                                toReturn = byte2;
                                toMove   = byte2Index;
                            }
                        }

                        _index = index + toMove;
                        return(toReturn);
                    }
                    // Need unit tests to test Vector path
#if !DEBUG
                }
#endif
                    var pCurrent = (segment.Block.DataFixedPtr + index);
                    var pEnd     = pCurrent + following;
                    do
                    {
                        if (*pCurrent == byte0)
                        {
                            _segment = segment;
                            _index   = index;
                            return(byte0);
                        }
                        if (*pCurrent == byte1)
                        {
                            _segment = segment;
                            _index   = index;
                            return(byte1);
                        }
                        if (*pCurrent == byte2)
                        {
                            _segment = segment;
                            _index   = index;
                            return(byte2);
                        }
                        pCurrent++;
                        index++;
                    } while (pCurrent != pEnd);

                    following = 0;
                    break;
                }
            }
        }