예제 #1
0
        // postcondition: bufferedLength >= _currentIndex + min(readAhead, AmountLeft(_stream))
        private void Buffer(int readAhead)
        {
            var readAheadTo = _currentIndex + readAhead;

            if (readAheadTo >= _bufferedCount)
            {
                // we're about to read past the end of the current chunk. Pull a new chunk from the stream
                var keepSeenLength = _bookmarks.Count > 0
                    ? Location - _bookmarks[0]
                    : 0;
                var keepFrom        = _currentIndex - keepSeenLength;
                var keepLength      = _bufferedCount - keepFrom;
                var amountToRead    = Math.Max(_bufferChunkSize, readAheadTo - keepFrom);
                var newBufferLength = _bufferedCount + amountToRead;

                //                  _currentIndex
                //                        |
                //                        | _bufferedCount
                //              keepFrom  |      |
                //                 |      |      | readAheadTo
                //                 |      |      |    |
                //              abcdefghijklmnopqrstuvwxyz
                //       readAhead        |-----------|
                //  keepSeenLength |------|
                //      keepLength |-------------|
                //    amountToRead               |----|
                // newBufferLength |------------------|


                for (var i = 0; i < keepFrom; i++)
                {
                    _bufferStartSourcePos = _posCalculator(_buffer[i], _bufferStartSourcePos);
                }

                if (newBufferLength > _buffer.Length)
                {
                    // grow the buffer
                    var newBuffer = ArrayPool <TToken> .Shared.Rent(Math.Max(newBufferLength, _buffer.Length * 2));

                    Array.Copy(_buffer, keepFrom, newBuffer, 0, keepLength);

                    ArrayPool <TToken> .Shared.Return(_buffer);

                    _buffer = newBuffer;
                }
                else if (keepFrom != 0 && keepLength != 0)
                {
                    // move the buffer's contents to the start

                    // todo: find out how expensive this Copy tends to be.
                    // Could prevent it by using a ring buffer, but might make reads slower
                    Array.Copy(_buffer, keepFrom, _buffer, 0, keepLength);
                }
                _bufferStartLocation += keepFrom;
                _currentIndex         = keepSeenLength;
                _bufferedCount        = keepLength;
                _bufferedCount       += _stream.ReadInto(_buffer, _bufferedCount, amountToRead);
            }
        }