Exemplo n.º 1
1
        public static void RentAndReturnManyOfTheSameSize_NoneAreSame(ArrayPool<byte> pool)
        {
            foreach (int length in new[] { 1, 16, 32, 64, 127, 4096, 4097 })
            {
                for (int iter = 0; iter < 2; iter++)
                {
                    var buffers = new HashSet<byte[]>();
                    for (int i = 0; i < 100; i++)
                    {
                        buffers.Add(pool.Rent(length));
                    }

                    Assert.Equal(100, buffers.Count);

                    foreach (byte[] buffer in buffers)
                    {
                        pool.Return(buffer);
                    }
                }
            }
        }
        public FileBufferingReadStream(
            Stream inner,
            int memoryThreshold,
            long? bufferLimit,
            Func<string> tempFileDirectoryAccessor,
            ArrayPool<byte> bytePool)
        {
            if (inner == null)
            {
                throw new ArgumentNullException(nameof(inner));
            }

            if (tempFileDirectoryAccessor == null)
            {
                throw new ArgumentNullException(nameof(tempFileDirectoryAccessor));
            }

            _bytePool = bytePool;
            if (memoryThreshold < _maxRentedBufferSize)
            {
                _rentedBuffer = bytePool.Rent(memoryThreshold);
                _buffer = new MemoryStream(_rentedBuffer);
                _buffer.SetLength(0);
            }
            else
            {
                _buffer = new MemoryStream();
            }

            _inner = inner;
            _memoryThreshold = memoryThreshold;
            _bufferLimit = bufferLimit;
            _tempFileDirectoryAccessor = tempFileDirectoryAccessor;
        }
Exemplo n.º 3
0
        public FixedSizeArrayBufferWriter(int size, ArrayPool <T>?pool = null)
        {
            if (size == 0)
            {
                size = 1; // to fit the IBufferWriter contract that GetMemory/GetSpan never return empty
            }

            _size   = size;
            _buffer = pool?.Rent(size) ?? new T[size];
        }
Exemplo n.º 4
0
 public StreamFormatter(Stream stream, FormattingData formattingData, ArrayPool<byte> pool, int bufferSize = 256)
 {
     _pool = pool;
     _buffer = null;
     if (bufferSize > 0)
     {
         _buffer = _pool.Rent(bufferSize);
     }
     _formattingData = formattingData;
     _stream = stream;
 }
Exemplo n.º 5
0
 public StreamFormatter(Stream stream, EncodingData encoding, ArrayPool<byte> pool, int bufferSize = 256)
 {
     _pool = pool;
     _buffer = null;
     if (bufferSize > 0)
     {
         _buffer = _pool.Rent(bufferSize);
     }
     _encoding = encoding;
     _stream = stream;
 }
Exemplo n.º 6
0
        public FormReader(string data, ArrayPool<char> charPool)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            _buffer = charPool.Rent(_rentedCharPoolLength);
            _charPool = charPool;
            _reader = new StringReader(data);
        }
Exemplo n.º 7
0
        public FormReader(Stream stream, Encoding encoding, ArrayPool<char> charPool)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            if (encoding == null)
            {
                throw new ArgumentNullException(nameof(encoding));
            }

            _buffer = charPool.Rent(_rentedCharPoolLength);
            _charPool = charPool;
            _reader = new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024 * 2, leaveOpen: true);
        }
Exemplo n.º 8
0
 /// <summary>
 /// Rents the pixel array from the pool.
 /// </summary>
 /// <param name="minimumLength">The minimum length of the array to return.</param>
 /// <returns>The <see cref="T:TColor[]"/></returns>
 public static TColor[] RentPixels(int minimumLength)
 {
     return(ArrayPool.Rent(minimumLength));
 }
Exemplo n.º 9
0
 public static T[] ReturnAndRent <T>(this ArrayPool <T> pool, T[] array, int newMinimumLength)
 {
     pool.Return(array);
     return(pool.Rent(newMinimumLength));
 }
Exemplo n.º 10
0
 public static void CanRentManySizedBuffers(ArrayPool<byte> pool)
 {
     for (int i = 1; i < 10000; i++)
     {
         byte[] buffer = pool.Rent(i);
         Assert.Equal(i <= 16 ? 16 : RoundUpToPowerOf2(i), buffer.Length);
         pool.Return(buffer);
     }
 }
        /// <summary>
        /// Buffers a portion of the given stream, returning the buffered stream partition.
        /// </summary>
        /// <param name="stream">
        /// Stream to buffer from.
        /// </param>
        /// <param name="minCount">
        /// Minimum number of bytes to buffer. This method will not return until at least this many bytes have been read from <paramref name="stream"/> or the stream completes.
        /// </param>
        /// <param name="maxCount">
        /// Maximum number of bytes to buffer.
        /// </param>
        /// <param name="absolutePosition">
        /// Current position of the stream, since <see cref="Stream.Position"/> throws if not seekable.
        /// </param>
        /// <param name="arrayPool">
        /// Pool to rent buffer space from.
        /// </param>
        /// <param name="maxArrayPoolRentalSize">
        /// Max size we can request from the array pool.
        /// </param>
        /// <param name="async">
        /// Whether to perform this operation asynchronously.
        /// </param>
        /// <param name="cancellationToken">
        /// Cancellation token.
        /// </param>
        /// <returns>
        /// The buffered stream partition with memory backed by an array pool.
        /// </returns>
        internal static async Task <PooledMemoryStream> BufferStreamPartitionInternal(
            Stream stream,
            long minCount,
            long maxCount,
            long absolutePosition,
            ArrayPool <byte> arrayPool,
            int?maxArrayPoolRentalSize,
            bool async,
            CancellationToken cancellationToken)
        {
            long totalRead       = 0;
            var  streamPartition = new PooledMemoryStream(arrayPool, absolutePosition, maxArrayPoolRentalSize ?? DefaultMaxArrayPoolRentalSize);

            // max count to write into a single array
            int maxCountIndividualBuffer;
            // min count to write into a single array
            int minCountIndividualBuffer;
            // the amount that was written into the current array
            int readIndividualBuffer;

            do
            {
                // buffer to write to
                byte[] buffer;
                // offset to start writing at
                int             offset;
                BufferPartition latestBuffer = streamPartition.GetLatestBufferWithAvailableSpaceOrDefault();
                // whether we got a brand new buffer to write into
                bool newbuffer;
                if (latestBuffer != default)
                {
                    buffer    = latestBuffer.Buffer;
                    offset    = latestBuffer.DataLength;
                    newbuffer = false;
                }
                else
                {
                    buffer    = arrayPool.Rent((int)Math.Min(maxCount - totalRead, streamPartition.MaxArraySize));
                    offset    = 0;
                    newbuffer = true;
                }

                // limit max and min count for this buffer by buffer length
                maxCountIndividualBuffer = (int)Math.Min(maxCount - totalRead, buffer.Length - offset);
                // definitionally limited by max; we won't ever have a swapped min/max range
                minCountIndividualBuffer = (int)Math.Min(minCount - totalRead, maxCountIndividualBuffer);

                readIndividualBuffer = await ReadLoopInternal(
                    stream,
                    buffer,
                    offset : offset,
                    minCountIndividualBuffer,
                    maxCountIndividualBuffer,
                    async,
                    cancellationToken).ConfigureAwait(false);

                // if nothing was placed in a brand new array
                if (readIndividualBuffer == 0 && newbuffer)
                {
                    arrayPool.Return(buffer);
                }
                // if brand new array and we did place data in it
                else if (newbuffer)
                {
                    streamPartition.BufferSet.Add(new BufferPartition
                    {
                        Buffer     = buffer,
                        DataLength = readIndividualBuffer
                    });
                }
                // added to an existing array that was not entirely filled
                else
                {
                    latestBuffer.DataLength += readIndividualBuffer;
                }

                totalRead += readIndividualBuffer;

                /* If we filled the buffer this loop, then quitting on min count is pointless. The point of quitting
                 * on min count is when the source stream doesn't have available bytes and we've reached an amount worth
                 * sending instead of blocking on. If we filled the available array, we don't actually know whether more
                 * data is available yet, as we limited our read for reasons outside the stream state. We should therefore
                 * try another read regardless of whether we hit min count.
                 */
            } while (
                // stream is done if this value is zero; no other check matters
                readIndividualBuffer != 0 &&
                // stop filling the partition if we've hit the max size of the partition
                totalRead < maxCount &&
                // stop filling the partition if we've reached min count and we know we've hit at least a pause in the stream
                (totalRead < minCount || readIndividualBuffer == maxCountIndividualBuffer));

            return(streamPartition);
        }
        public HttpRequestStreamReader(
            Stream stream,
            Encoding encoding,
            int bufferSize,
            ArrayPool<byte> bytePool,
            ArrayPool<char> charPool)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            if (!stream.CanRead)
            {
                throw new ArgumentException(Resources.HttpRequestStreamReader_StreamNotReadable, nameof(stream));
            }

            if (encoding == null)
            {
                throw new ArgumentNullException(nameof(encoding));
            }

            if (bytePool == null)
            {
                throw new ArgumentNullException(nameof(bytePool));
            }

            if (charPool == null)
            {
                throw new ArgumentNullException(nameof(charPool));
            }

            if (bufferSize <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(bufferSize));
            }

            _stream = stream;
            _encoding = encoding;
            _byteBufferSize = bufferSize;
            _bytePool = bytePool;
            _charPool = charPool;

            _decoder = encoding.GetDecoder();

            _byteBuffer = _bytePool.Rent(bufferSize);

            try
            {
                var requiredLength = encoding.GetMaxCharCount(bufferSize);
                _charBuffer = _charPool.Rent(requiredLength);
            }
            catch
            {
                _bytePool.Return(_byteBuffer);
                _byteBuffer = null;

                if (_charBuffer != null)
                {
                    _charPool.Return(_charBuffer);
                    _charBuffer = null;
                }
            }
        }
        public HttpResponseStreamWriter(
            Stream stream,
            Encoding encoding,
            int bufferSize,
            ArrayPool<byte> bytePool,
            ArrayPool<char> charPool)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            if (!stream.CanWrite)
            {
                throw new ArgumentException(Resources.HttpResponseStreamWriter_StreamNotWritable, nameof(stream));
            }

            if (encoding == null)
            {
                throw new ArgumentNullException(nameof(encoding));
            }

            if (bytePool == null)
            {
                throw new ArgumentNullException(nameof(bytePool));
            }

            if (charPool == null)
            {
                throw new ArgumentNullException(nameof(charPool));
            }

            _stream = stream;
            Encoding = encoding;
            _charBufferSize = bufferSize;

            _encoder = encoding.GetEncoder();
            _bytePool = bytePool;
            _charPool = charPool;

            _charBuffer = charPool.Rent(bufferSize);

            try
            {
                var requiredLength = encoding.GetMaxByteCount(bufferSize);
                _byteBuffer = bytePool.Rent(requiredLength);
            }
            catch
            {
                charPool.Return(_charBuffer);
                _charBuffer = null;

                if (_byteBuffer != null)
                {
                    bytePool.Return(_byteBuffer);
                    _byteBuffer = null;
                }

                throw;
            }
        }
Exemplo n.º 14
0
        public static BytesOwner ReadPageData(Stream nakedStream, Thrift.CompressionCodec compressionCodec,
                                              int compressedLength, int uncompressedLength)
        {
            if (!_codecToCompressionMethod.TryGetValue(compressionCodec, out CompressionMethod compressionMethod))
            {
                throw new NotSupportedException($"reader for compression '{compressionCodec}' is not supported.");
            }

            int totalBytesRead   = 0;
            int currentBytesRead = int.MinValue;

            byte[] data       = BytesPool.Rent(compressedLength);
            bool   dataRented = true;

            // Some storage solutions (like Azure blobs) might require more than one 'Read' action to read the requested length.
            while (totalBytesRead < compressedLength && currentBytesRead != 0)
            {
                currentBytesRead = nakedStream.Read(data, totalBytesRead, compressedLength - totalBytesRead);
                totalBytesRead  += currentBytesRead;
            }

            if (totalBytesRead != compressedLength)
            {
                throw new ParquetException($"expected {compressedLength} bytes in source stream but could read only {totalBytesRead}");
            }

            switch (compressionMethod)
            {
            case CompressionMethod.None:
                //nothing to do, original data is the raw data
                break;

            case CompressionMethod.Gzip:
                using (var source = new MemoryStream(data, 0, compressedLength))
                {
                    byte[] unGzData = BytesPool.Rent(uncompressedLength);
                    using (var dest = new MemoryStream(unGzData, 0, uncompressedLength))
                    {
                        using (var gz = new GZipStream(source, CompressionMode.Decompress))
                        {
                            gz.CopyTo(dest);
                        }
                    }
                    BytesPool.Return(data);
                    data = unGzData;
                }
                break;

            case CompressionMethod.Snappy:
                byte[] uncompressed = Snappy.Decode(data.AsSpan(0, compressedLength));
                BytesPool.Return(data);
                data       = uncompressed;
                dataRented = false;
                break;

            default:
                throw new NotSupportedException("method: " + compressionMethod);
            }

            return(new BytesOwner(data, 0, data.AsMemory(0, uncompressedLength), d => BytesPool.Return(d), dataRented));
        }
Exemplo n.º 15
0
 public TShared[] Rent(int minimumLength) => _inner.Rent(minimumLength);
Exemplo n.º 16
0
        protected int ReadNextPacket()
        {
            if (Data != null)
            {
                StreamingPool.Return(Data);
                Data = null;
            }

            //wait until a magic packet is received
            Device.MillisTimeout = 100;
            while (true)
            {
                Span <byte> MagicBuf = stackalloc byte[4];
                if (Device.Read(MagicBuf) != 4)
                {
                    if (Token.IsCancellationRequested)
                    {
                        return(-3);
                    }
                    else
                    {
                        continue;
                    }
                }
                if (MagicBuf.SequenceEqual(MagicPacket))
                {
                    break;
                }
            }

            //read the payload size
            Span <byte> SizeBuf = stackalloc byte[4];

            if (Device.Read(SizeBuf) != 4)
            {
                return(-2);
            }
            var size = BitConverter.ToUInt32(SizeBuf);

            if (size > MaxBufSize)
            {
                return(-1);
            }
            if (size == 0)
            {
                return(0);
            }

            //read the timestamp
            Span <byte> TsBuf = stackalloc byte[8];

            if (Device.Read(TsBuf) != 8)
            {
                return(-4);
            }
            Timestamp = BitConverter.ToUInt64(TsBuf);
            if (firtTs == 0)
            {
                firtTs = Timestamp;
            }

            Timestamp -= firtTs;

            //Read the actual data
            Device.MillisTimeout = 1000;
            Data = StreamingPool.Rent((int)size);
            int actualsize = Device.Read(Data, 0, (int)size);

            if (actualsize != size)
            {
                Console.WriteLine("Warning: Reported size doesn't match received size");
            }
            return(actualsize);
        }
Exemplo n.º 17
0
 public static void RentingWithInvalidLengthThrows(ArrayPool <byte> pool)
 {
     AssertExtensions.Throws <ArgumentOutOfRangeException>("minimumLength", () => pool.Rent(-1));
 }
Exemplo n.º 18
0
 public DisposableArrayPool(ArrayPool <T> pool, int minimumLength)
 {
     _pool = pool;
     Array = pool.Rent(minimumLength);
 }
Exemplo n.º 19
0
 BufferSegment CreateSegment()
 {
     return(new BufferSegment(_pool.Rent(_segmentSize)));
 }
Exemplo n.º 20
0
 public T[] Rent(int minimumLength)
 {
     return(_inner.Rent(minimumLength));
 }
Exemplo n.º 21
0
 public ArrayFormatter(int capacity, SymbolTable symbolTable, ArrayPool <byte> pool = null)
 {
     _pool        = pool ?? ArrayPool <byte> .Shared;
     _symbolTable = symbolTable;
     _buffer      = new ResizableArray <byte>(_pool.Rent(capacity));
 }
Exemplo n.º 22
0
 public StringFormatter(int capacity, ArrayPool<byte> pool)
 {
     _pool = pool;
     _buffer = _pool.Rent(capacity * 2);
 }
Exemplo n.º 23
0
 static TemporaryArray <T> CreateInternal <T>(ArrayPool <T> pool, int length, bool clearOnReturn)
 => new TemporaryArray <T>(pool, pool?.Rent(length) ?? new T[length], length, clearOnReturn);
Exemplo n.º 24
0
 public ArrayFormatter(int capacity, EncodingData encoding, ArrayPool<byte> pool = null)
 {
     _pool = pool != null ? pool : ArrayPool<byte>.Shared;
     _encoding = encoding;
     _buffer = new ResizableArray<byte>(_pool.Rent(capacity));
 }
Exemplo n.º 25
0
 public static void CallingReturnWithoutClearingDoesNotClearTheBuffer(ArrayPool<byte> pool)
 {
     byte[] buffer = pool.Rent(4);
     FillArray(buffer);
     pool.Return(buffer, clearArray: false);
     CheckFilledArray(buffer, (byte b1, byte b2) => Assert.Equal(b1, b2));
 }
Exemplo n.º 26
0
        public static void RentingWithInvalidLengthThrows(int length)
        {
            ArrayPool <byte> pool = ArrayPool <byte> .Create();

            Assert.Throws <ArgumentOutOfRangeException>("minimumLength", () => pool.Rent(length));
        }
Exemplo n.º 27
0
        public override int Read(Span <byte> buffer)
        {
            ThrowIfDisposed();

            if (_buffer.Position < _buffer.Length || _completelyBuffered)
            {
                // Just read from the buffer
                return(_buffer.Read(buffer));
            }

            var read = _inner.Read(buffer);

            if (_bufferLimit.HasValue && _bufferLimit - read < _buffer.Length)
            {
                throw new IOException("Buffer limit exceeded.");
            }

            // We're about to go over the threshold, switch to a file
            if (_inMemory && _memoryThreshold - read < _buffer.Length)
            {
                _inMemory = false;
                var oldBuffer = _buffer;
                _buffer = CreateTempFile();
                if (_rentedBuffer == null)
                {
                    // Copy data from the in memory buffer to the file stream using a pooled buffer
                    oldBuffer.Position = 0;
                    var rentedBuffer = _bytePool.Rent(Math.Min((int)oldBuffer.Length, _maxRentedBufferSize));
                    try
                    {
                        var copyRead = oldBuffer.Read(rentedBuffer);
                        while (copyRead > 0)
                        {
                            _buffer.Write(rentedBuffer.AsSpan(0, copyRead));
                            copyRead = oldBuffer.Read(rentedBuffer);
                        }
                    }
                    finally
                    {
                        _bytePool.Return(rentedBuffer);
                    }
                }
                else
                {
                    _buffer.Write(_rentedBuffer.AsSpan(0, (int)oldBuffer.Length));
                    _bytePool.Return(_rentedBuffer);
                    _rentedBuffer = null;
                }
            }

            if (read > 0)
            {
                _buffer.Write(buffer.Slice(0, read));
            }
            else
            {
                _completelyBuffered = true;
            }

            return(read);
        }
Exemplo n.º 28
0
        public static void RentingMultipleArraysGivesBackDifferentInstances()
        {
            ArrayPool <byte> instance = ArrayPool <byte> .Create(maxArraysPerBucket : 2, maxArrayLength : 16);

            Assert.NotSame(instance.Rent(100), instance.Rent(100));
        }
Exemplo n.º 29
0
 public static void UsePoolInParallel(ArrayPool<byte> pool)
 {
     int[] sizes = new int[] { 16, 32, 64, 128 };
     Parallel.For(0, 250000, i =>
     {
         foreach (int size in sizes)
         {
             byte[] array = pool.Rent(size);
             Assert.NotNull(array);
             Assert.InRange(array.Length, size, int.MaxValue);
             pool.Return(array);
         }
     });
 }
Exemplo n.º 30
0
        public static void CallingReturnWithClearingDoesClearTheBuffer(ArrayPool<byte> pool)
        {
            byte[] buffer = pool.Rent(4);
            FillArray(buffer);

            // Note - yes this is bad to hold on to the old instance but we need to validate the contract
            pool.Return(buffer, clearArray: true);
            CheckFilledArray(buffer, (byte b1, byte b2) => Assert.Equal(b1, default(byte)));
        }
Exemplo n.º 31
0
        public static void Renting0LengthArrayReturnsSingleton(ArrayPool<byte> pool)
        {
            byte[] zero0 = pool.Rent(0);
            byte[] zero1 = pool.Rent(0);
            byte[] zero2 = pool.Rent(0);
            byte[] one = pool.Rent(1);

            Assert.Same(zero0, zero1);
            Assert.Same(zero1, zero2);
            Assert.NotSame(zero2, one);

            pool.Return(zero0);
            pool.Return(zero1);
            pool.Return(zero2);
            pool.Return(one);

            Assert.Same(zero0, pool.Rent(0));
        }
Exemplo n.º 32
0
        /// <summary>
        /// Internal part of the DHT processor, whatever does it mean
        /// </summary>
        /// <param name="inputProcessor">The decoder instance</param>
        /// <param name="defineHuffmanTablesData">The temporal buffer that holds the data that has been read from the Jpeg stream</param>
        /// <param name="remaining">Remaining bits</param>
        public void ProcessDefineHuffmanTablesMarkerLoop(
            ref InputProcessor inputProcessor,
            byte[] defineHuffmanTablesData,
            ref int remaining)
        {
            // Read nCodes and huffman.Valuess (and derive h.Length).
            // nCodes[i] is the number of codes with code length i.
            // h.Length is the total number of codes.
            this.Length = 0;

            int[] ncodes = new int[MaxCodeLength];
            for (int i = 0; i < ncodes.Length; i++)
            {
                ncodes[i]    = defineHuffmanTablesData[i + 1];
                this.Length += ncodes[i];
            }

            if (this.Length == 0)
            {
                throw new ImageFormatException("Huffman table has zero length");
            }

            if (this.Length > MaxNCodes)
            {
                throw new ImageFormatException("Huffman table has excessive length");
            }

            remaining -= this.Length + 17;
            if (remaining < 0)
            {
                throw new ImageFormatException("DHT has wrong length");
            }

            byte[] values = null;
            try
            {
                values = BytePool256.Rent(MaxNCodes);
                inputProcessor.ReadFull(values, 0, this.Length);

                for (int i = 0; i < values.Length; i++)
                {
                    this.Values[i] = values[i];
                }
            }
            finally
            {
                BytePool256.Return(values, true);
            }

            // Derive the look-up table.
            for (int i = 0; i < this.Lut.Length; i++)
            {
                this.Lut[i] = 0;
            }

            int x = 0, code = 0;

            for (int i = 0; i < LutSizeLog2; i++)
            {
                code <<= 1;

                for (int j = 0; j < ncodes[i]; j++)
                {
                    // The codeLength is 1+i, so shift code by 8-(1+i) to
                    // calculate the high bits for every 8-bit sequence
                    // whose codeLength's high bits matches code.
                    // The high 8 bits of lutValue are the encoded value.
                    // The low 8 bits are 1 plus the codeLength.
                    int base2    = code << (7 - i);
                    int lutValue = (this.Values[x] << 8) | (2 + i);

                    for (int k = 0; k < 1 << (7 - i); k++)
                    {
                        this.Lut[base2 | k] = lutValue;
                    }

                    code++;
                    x++;
                }
            }

            // Derive minCodes, maxCodes, and indices.
            int c = 0, index = 0;

            for (int i = 0; i < ncodes.Length; i++)
            {
                int nc = ncodes[i];
                if (nc == 0)
                {
                    this.MinCodes[i] = -1;
                    this.MaxCodes[i] = -1;
                    this.Indices[i]  = -1;
                }
                else
                {
                    this.MinCodes[i] = c;
                    this.MaxCodes[i] = c + nc - 1;
                    this.Indices[i]  = index;
                    c     += nc;
                    index += nc;
                }

                c <<= 1;
            }
        }
Exemplo n.º 33
0
        public static async Task <ReadOnlyMemory <byte> > ComputeHashAsync(
            this Stream stream,
            IHashAlgorithm hashAlgorithm,
            ArrayPool <byte> arrayPool,
            int bufferSize,
            CancellationToken cancellationToken
            )
        {
            // Validate parameters.
            if (hashAlgorithm == null)
            {
                throw new ArgumentNullException(nameof(hashAlgorithm));
            }
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }
            if (arrayPool == null)
            {
                throw new ArgumentNullException(nameof(arrayPool));
            }
            if (bufferSize <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(bufferSize), bufferSize, $"The { nameof(bufferSize) } parameter must be a positive value.");
            }

            // The declarations for the buffer and the copy.
            byte[]? buffer = null;
            byte[]? copy   = null;

            // Wrap in a try/finally.
            try
            {
                // Allocate.
                buffer = arrayPool.Rent(bufferSize);
                copy   = arrayPool.Rent(bufferSize);

                // The bytes read task.
                Task <int> bytesRead = stream.ReadAsync(buffer, 0, bufferSize, cancellationToken);

                // No bytes read, get out.
                if ((await bytesRead.ConfigureAwait(false)) == 0)
                {
                    return(hashAlgorithm.Hash);
                }

                // While there are items to process.
                do
                {
                    // Copy the buffer.
                    // NOTE: Need to do this because it's a shared resource.
                    // If tests show there's a sweet spot between the copy time and hash time < next ReadAsync time,
                    // move buffer size accordingly.
                    Array.Copy(buffer, copy, bufferSize);

                    // Read the next task.
                    bytesRead = stream.ReadAsync(buffer, 0, bufferSize, cancellationToken);

                    // Hash.
                    hashAlgorithm.TransformBlock(copy);

                    // Get the next stream immediately.
                } while (await bytesRead.ConfigureAwait(false) > 0);

                // Return.
                return(hashAlgorithm.Hash);
            }
            finally
            {
                // Release.
                arrayPool.Return(buffer);
                arrayPool.Return(copy);
            }
        }
Exemplo n.º 34
0
 public static void RentingWithInvalidLengthThrows(ArrayPool<byte> pool)
 {
     Assert.Throws<ArgumentOutOfRangeException>("minimumLength", () => pool.Rent(-1));
 }
Exemplo n.º 35
0
 /// <summary>
 /// 申请
 /// </summary>
 /// <param name="minimumLength"></param>
 /// <returns></returns>
 public static byte[] Rent(int minimumLength)
 {
     return(ArrayPool.Rent(minimumLength));
 }
Exemplo n.º 36
0
    internal const byte ReservedEscapeMessageBytes       = 5;                                                                                                      // 2 characters total, escape one '\' of 1 byte and real one of up to 4 bytes

    internal static async IAsyncEnumerable <string> GetMessageParts(string message, string?steamMessagePrefix = null, bool isAccountLimited = false)
    {
        if (string.IsNullOrEmpty(message))
        {
            throw new ArgumentNullException(nameof(message));
        }

        int prefixBytes  = 0;
        int prefixLength = 0;

        if (!string.IsNullOrEmpty(steamMessagePrefix))
        {
            // We must escape our message prefix if needed
            // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
            steamMessagePrefix = Escape(steamMessagePrefix !);

            prefixBytes = GetMessagePrefixBytes(steamMessagePrefix);

            if (prefixBytes > MaxMessagePrefixBytes)
            {
                throw new ArgumentOutOfRangeException(nameof(steamMessagePrefix));
            }

            prefixLength = steamMessagePrefix.Length;
        }

        int maxMessageBytes = (isAccountLimited ? MaxMessageBytesForLimitedAccounts : MaxMessageBytesForUnlimitedAccounts) - ReservedContinuationMessageBytes;

        // We must escape our message prior to sending it
        message = Escape(message);

        int           messagePartBytes = prefixBytes;
        StringBuilder messagePart      = new(steamMessagePrefix);

        Decoder          decoder  = Encoding.UTF8.GetDecoder();
        ArrayPool <char> charPool = ArrayPool <char> .Shared;

        using StringReader stringReader = new(message);

        while (await stringReader.ReadLineAsync().ConfigureAwait(false) is { } line)
        {
            // Special case for empty newline
            if (line.Length == 0)
            {
                if (messagePart.Length > prefixLength)
                {
                    messagePartBytes += NewlineWeight;
                    messagePart.AppendLine();
                }

                // Check if we reached the limit for one message
                if (messagePartBytes + NewlineWeight + ReservedEscapeMessageBytes > maxMessageBytes)
                {
                    if (stringReader.Peek() >= 0)
                    {
                        messagePart.Append(ParagraphCharacter);
                    }

                    yield return(messagePart.ToString());

                    messagePartBytes = prefixBytes;
                    messagePart.Clear();
                    messagePart.Append(steamMessagePrefix);
                }

                // Move on to the next line
                continue;
            }

            byte[] lineBytes = Encoding.UTF8.GetBytes(line);

            for (int lineBytesRead = 0; lineBytesRead < lineBytes.Length;)
            {
                if (messagePart.Length > prefixLength)
                {
                    if (messagePartBytes + NewlineWeight + lineBytes.Length > maxMessageBytes)
                    {
                        messagePart.Append(ParagraphCharacter);

                        yield return(messagePart.ToString());

                        messagePartBytes = prefixBytes;
                        messagePart.Clear();
                        messagePart.Append(steamMessagePrefix);
                    }
                    else
                    {
                        messagePartBytes += NewlineWeight;
                        messagePart.AppendLine();
                    }
                }

                int bytesToTake = Math.Min(maxMessageBytes - messagePartBytes, lineBytes.Length - lineBytesRead);

                // We can never have more characters than bytes used, so this covers the worst case of 1-byte characters exclusively
                char[] lineChunk = charPool.Rent(bytesToTake);

                try {
                    // We have to reset the decoder prior to using it, as we must discard any amount of bytes read from previous incomplete character
                    decoder.Reset();

                    int charsUsed = decoder.GetChars(lineBytes, lineBytesRead, bytesToTake, lineChunk, 0, false);

                    switch (charsUsed)
                    {
                    case <= 0:
                        throw new InvalidOperationException(nameof(charsUsed));

                    case >= 2 when(lineChunk[charsUsed - 1] == '\\') && (lineChunk[charsUsed - 2] != '\\'):
                        // If our message is of max length and ends with a single '\' then we can't split it here, because it escapes the next character
                        // Instead, we'll cut this message one char short and include the rest in the next iteration
                        charsUsed--;

                        break;
                    }

                    int bytesUsed = Encoding.UTF8.GetByteCount(lineChunk, 0, charsUsed);

                    if (lineBytesRead > 0)
                    {
                        messagePartBytes += ContinuationCharacterBytes;
                        messagePart.Append(ContinuationCharacter);
                    }

                    lineBytesRead += bytesUsed;

                    messagePartBytes += bytesUsed;
                    messagePart.Append(lineChunk, 0, charsUsed);
                } finally {
                    charPool.Return(lineChunk);
                }

                bool midLineSplitting = false;

                if (lineBytesRead < lineBytes.Length)
                {
                    midLineSplitting = true;

                    messagePartBytes += ContinuationCharacterBytes;
                    messagePart.Append(ContinuationCharacter);
                }

                // Check if we still have room for one more line
                if (messagePartBytes + NewlineWeight + ReservedEscapeMessageBytes <= maxMessageBytes)
                {
                    continue;
                }

                if (!midLineSplitting && (stringReader.Peek() >= 0))
                {
                    messagePart.Append(ParagraphCharacter);
                }

                yield return(messagePart.ToString());

                messagePartBytes = prefixBytes;
                messagePart.Clear();
                messagePart.Append(steamMessagePrefix);
            }
        }

        if (messagePart.Length <= prefixLength)
        {
            yield break;
        }

        yield return(messagePart.ToString());
    }
Exemplo n.º 37
0
 private static ArraySegment <byte> Rent(int size)
 {
     byte[] buffer = s_bufferPool.Rent(size);
     return(new ArraySegment <byte>(buffer, 0, size));
 }