Beispiel #1
0
 /// <summary>
 /// Initializes growable buffer.
 /// </summary>
 /// <param name="buffer">Pre-allocated buffer used by this builder.</param>
 /// <param name="allocator">The memory allocator used to rent the memory blocks.</param>
 /// <remarks>
 /// The builder created with this constructor is growable. However, additional memory will not be
 /// requested using <paramref name="allocator"/> while <paramref name="buffer"/> space is sufficient.
 /// If <paramref name="allocator"/> is <see langword="null"/> then <see cref="ArrayPool{T}.Shared"/>
 /// is used for memory pooling.
 /// </remarks>
 public BufferWriterSlim(Span <T> buffer, MemoryAllocator <T>?allocator = null)
 {
     initialBuffer  = buffer;
     this.allocator = allocator;
     extraBuffer    = default;
     position       = 0;
 }
 protected override void Dispose(bool disposing)
 {
     owner.Dispose();
     owner        = default;
     writtenCount = 0;
     base.Dispose(disposing);
 }
Beispiel #3
0
 /// <summary>
 /// Clears the data written to the underlying buffer.
 /// </summary>
 /// <exception cref="ObjectDisposedException">This writer has been disposed.</exception>
 public override void Clear()
 {
     ThrowIfDisposed();
     buffer.Dispose();
     buffer   = default;
     position = 0;
 }
Beispiel #4
0
 public static void RentFromMemoryPool2()
 {
     using var owner = new MemoryOwner <byte>(MemoryPool <byte> .Shared.Rent, 10);
     Equal(10, owner.Memory.Length);
     owner[1] = 42;
     Equal(42, owner[1]);
 }
Beispiel #5
0
        /// <inheritdoc/>
        private protected override void Resize(int newSize)
        {
            var newBuffer = allocator.Invoke(newSize, false);

            buffer.Memory.CopyTo(newBuffer.Memory);
            buffer.Dispose();
            buffer = newBuffer;
        }
 /// <summary>
 /// Initializes growable builder.
 /// </summary>
 /// <param name="buffer">Pre-allocated buffer used by this builder.</param>
 /// <param name="copyOnOverflow">
 /// <see langword="true"/> to copy pre-allocated buffer to pooled memory on overflow;
 /// <see langword="false"/> to keep head of the written content in the pre-allocated buffer.
 /// </param>
 /// <param name="allocator">The memory allocator used to rent the memory blocks.</param>
 /// <remarks>
 /// The builder created with this constructor is growable. However, additional memory will not be
 /// requested using <paramref name="allocator"/> while <paramref name="buffer"/> space is sufficient.
 /// If <paramref name="allocator"/> is <see langword="null"/> then <see cref="ArrayPool{T}.Shared"/>
 /// is used for memory pooling.
 /// <see cref="WrittenSpan"/> property is supported only if <paramref name="copyOnOverflow"/> is <see langword="true"/>.
 /// Otherwise, it's not possible to represent written content as contiguous memory block.
 /// </remarks>
 public BufferWriterSlim(Span <T> buffer, bool copyOnOverflow, MemoryAllocator <T>?allocator = null)
 {
     initialBuffer       = buffer;
     this.allocator      = allocator;
     extraBuffer         = default;
     position            = 0;
     this.copyOnOverflow = copyOnOverflow;
 }
Beispiel #7
0
        public static void WrapArray()
        {
            var array = new byte[42];

            using var owner = new MemoryOwner <byte>(array);
            Equal(42, owner.Memory.Length);
            owner[2] = 10;
            Equal(10, array[2]);
        }
        /// <inheritdoc/>
        private protected override void Resize(int newSize)
        {
            var newBuffer = allocator.Invoke(newSize, false);

            buffer.Memory.CopyTo(newBuffer.Memory);
            buffer.Dispose();
            buffer = newBuffer;
            AllocationCounter?.WriteMetric(newBuffer.Length);
        }
 /// <summary>
 /// Initializes a new writer with the specified initial capacity.
 /// </summary>
 /// <param name="allocator">The allocator of internal buffer.</param>
 /// <param name="initialCapacity">The initial capacity of the writer.</param>
 /// <exception cref="ArgumentOutOfRangeException"><paramref name="initialCapacity"/> is less than or equal to zero.</exception>
 public PooledBufferWriter(MemoryAllocator <T>?allocator, int initialCapacity)
 {
     if (initialCapacity <= 0)
     {
         throw new ArgumentOutOfRangeException(nameof(initialCapacity));
     }
     this.allocator = allocator;
     buffer         = allocator.Invoke(initialCapacity, false);
 }
        /// <summary>
        /// Allocates memory.
        /// </summary>
        /// <param name="allocator">The memory allocator.</param>
        /// <param name="length">The number of items in the rented memory.</param>
        /// <param name="exactSize">
        /// <see langword="true"/> to ask allocator to allocate exactly <paramref name="length"/>;
        /// <see langword="false"/> to allocate at least <paramref name="length"/>.
        /// </param>
        /// <typeparam name="T">The type of the items in the memory pool.</typeparam>
        /// <returns>The allocated memory.</returns>
        public static MemoryOwner <T> Invoke <T>(this MemoryAllocator <T> allocator, int length, bool exactSize)
        {
            var result = allocator(length);

            if (!exactSize)
            {
                MemoryOwner <T> .Expand(ref result);
            }
            return(result);
        }
Beispiel #11
0
        /// <inheritdoc/>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                buffer.Dispose();
                buffer = default;
            }

            base.Dispose(disposing);
        }
        /// <inheritdoc/>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                BufferSizeCallback?.Invoke(buffer.Length);
                buffer.Dispose();
                buffer = default;
            }

            base.Dispose(disposing);
        }
Beispiel #13
0
        public override void Clear() => Clear(false);   // TODO: Remove this method in future

        /// <summary>
        /// Clears the data written to the underlying memory.
        /// </summary>
        /// <param name="reuseBuffer"><see langword="true"/> to reuse the internal buffer; <see langword="false"/> to destroy the internal buffer.</param>
        /// <exception cref="ObjectDisposedException">This writer has been disposed.</exception>
        public override void Clear(bool reuseBuffer)
        {
            ThrowIfDisposed();

            if (!reuseBuffer)
            {
                buffer.Dispose();
                buffer = default;
            }

            position = 0;
        }
Beispiel #14
0
        public static void RawReference()
        {
            var owner = new MemoryOwner <byte>(Array.Empty <byte>());

            True(Unsafe.IsNullRef(ref BufferHelpers.GetReference(in owner)));

            owner = default;
            True(Unsafe.IsNullRef(ref BufferHelpers.GetReference(in owner)));

            owner = new(new byte[] { 10 });
            Equal(10, BufferHelpers.GetReference(in owner));
        }
Beispiel #15
0
        /// <summary>
        /// Initializes growable buffer.
        /// </summary>
        /// <param name="initialCapacity">The initial capacity of the internal buffer.</param>
        /// <param name="allocator">The memory allocator used to rent the memory blocks.</param>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="initialCapacity"/> is less than zero.</exception>
        public BufferWriterSlim(int initialCapacity, MemoryAllocator <T>?allocator = null)
        {
            if (initialCapacity < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(initialCapacity));
            }

            initialBuffer  = default;
            this.allocator = allocator;

            extraBuffer                       = initialCapacity == 0 ? default : allocator.Invoke(initialCapacity, false);
                                     position = 0;
        }
Beispiel #16
0
        public static void SetBufferLength()
        {
            var buffer = default(MemoryOwner <byte>);

            True(buffer.TryResize(0));
            False(buffer.TryResize(10));
            Throws <ArgumentOutOfRangeException>(() => buffer.TryResize(-1));

            buffer = new MemoryOwner <byte>(new byte[] { 10, 20, 30 });
            True(buffer.TryResize(1));
            True(buffer.TryResize(3));
            False(buffer.TryResize(10));
        }
Beispiel #17
0
        /// <summary>
        /// Detaches the underlying buffer with written content from this writer.
        /// </summary>
        /// <param name="owner">The buffer owner.</param>
        /// <returns>
        /// <see langword="true"/> if the written content is in rented buffer because initial buffer overflows;
        /// <see langword="false"/> if the written content is in preallocated buffer.
        /// </returns>
        public bool TryDetachBuffer(out MemoryOwner <T> owner)
        {
            if (NoOverflow)
            {
                owner = default;
                return(false);
            }

            owner = extraBuffer;
            owner.Truncate(position);
            position    = 0;
            extraBuffer = default;
            return(true);
        }
        /// <summary>
        /// lears the data written to the underlying buffer.
        /// </summary>
        /// <param name="reuseBuffer"><see langword="true"/> to reuse the internal buffer; <see langword="false"/> to destroy the internal buffer.</param>
        public void Clear(bool reuseBuffer)
        {
            initialBuffer.Clear();
            if (!reuseBuffer)
            {
                extraBuffer.Dispose();
                extraBuffer = default;
            }
            else if (RuntimeHelpers.IsReferenceOrContainsReferences <T>())
            {
                extraBuffer.Memory.Span.Clear();
            }

            position = 0;
        }
        public override void Clear() => Clear(false);   // TODO: Remove this method in future

        /// <summary>
        /// Clears the data written to the underlying memory.
        /// </summary>
        /// <param name="reuseBuffer"><see langword="true"/> to reuse the internal buffer; <see langword="false"/> to destroy the internal buffer.</param>
        /// <exception cref="ObjectDisposedException">This writer has been disposed.</exception>
        public override void Clear(bool reuseBuffer)
        {
            ThrowIfDisposed();

            if (!reuseBuffer)
            {
                buffer.Dispose();
                buffer = default;
            }
            else if (RuntimeHelpers.IsReferenceOrContainsReferences <T>())
            {
                buffer.Memory.Span.Clear();
            }

            position = 0;
        }
Beispiel #20
0
        /// <summary>
        /// Returns the memory to write to that is at least the requested size.
        /// </summary>
        /// <param name="sizeHint">The minimum length of the returned memory.</param>
        /// <returns>The memory block of at least the size <paramref name="sizeHint"/>.</returns>
        /// <exception cref="OutOfMemoryException">The requested buffer size is not available.</exception>
        public Span <T> GetSpan(int sizeHint = 0)
        {
            if (sizeHint < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(sizeHint));
            }

            Span <T> result;
            int?     newSize;

            if (extraBuffer.IsEmpty)
            {
                newSize = IGrowableBuffer <T> .GetBufferSize(sizeHint, initialBuffer.Length, position);

                // need to copy initial buffer
                if (newSize.HasValue)
                {
                    extraBuffer = allocator.Invoke(newSize.GetValueOrDefault(), false);
                    initialBuffer.CopyTo(extraBuffer.Memory.Span);
                    initialBuffer.Clear();
                    result = extraBuffer.Memory.Span;
                }
                else
                {
                    result = initialBuffer;
                }
            }
            else
            {
                newSize = IGrowableBuffer <T> .GetBufferSize(sizeHint, extraBuffer.Length, position);

                // no need to copy initial buffer
                if (newSize.HasValue)
                {
                    var newBuffer = allocator.Invoke(newSize.GetValueOrDefault(), false);
                    extraBuffer.Memory.CopyTo(newBuffer.Memory);
                    extraBuffer.Dispose();
                    extraBuffer = newBuffer;
                }

                result = extraBuffer.Memory.Span;
            }

            return(result.Slice(position));
        }
        public Memory <byte> GetMemory(int sizeHint)
        {
            if (sizeHint < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(sizeHint));
            }
            if (sizeHint == 0)
            {
                sizeHint = 1;
            }
            if (sizeHint > buffer.Length - position)
            {
                buffer.Dispose();
                buffer = allocator(sizeHint);
            }

            return(buffer.Memory.Slice(position));
        }
Beispiel #22
0
        public static MemoryOwner <T> Invoke <T>(this MemoryAllocator <T>?allocator, int length, bool exactSize)
        {
            MemoryOwner <T> result;

            if (allocator is null)
            {
                result = new MemoryOwner <T>(ArrayPool <T> .Shared, length, exactSize);
                goto exit;
            }

            result = allocator(length);
            if (!exactSize)
            {
                result.Expand();
            }
exit:
            return(result);
        }
Beispiel #23
0
        /// <inheritdoc />
        public override MemoryOwner <T> DetachBuffer()
        {
            ThrowIfDisposed();
            MemoryOwner <T> result;

            if (position > 0)
            {
                result = buffer;
                buffer = default;
                result.Truncate(position);
                position = 0;
            }
            else
            {
                result = default;
            }

            return(result);
        }
Beispiel #24
0
        public void Advance(int count)
        {
            if (count < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }
            if (position > buffer.Length - count)
            {
                throw new InvalidOperationException();
            }

            output.Write(buffer.Memory.Span.Slice(position, count));
            position += count;

            // release buffer if it is cannot be reused
            if (position == buffer.Length)
            {
                buffer.Dispose();
                buffer   = default;
                position = 0;
            }
        }
        /// <summary>
        /// Writes elements to this buffer.
        /// </summary>
        /// <param name="input">The span of elements to be written.</param>
        /// <exception cref="InsufficientMemoryException">Pre-allocated initial buffer size is not enough to place <paramref name="input"/> elements to it and this builder is not growable.</exception>
        /// <exception cref="OverflowException">The size of the internal buffer becomes greater than <see cref="int.MaxValue"/>.</exception>
        public void Write(ReadOnlySpan <T> input)
        {
            var             newSize = checked (position + input.Length);
            Span <T>        output;
            int             offset;
            MemoryOwner <T> newBuffer;

            if (copyOnOverflow)
            {
                // grow if needed
                if (newSize > initialBuffer.Length)
                {
                    if (extraBuffer.IsEmpty)
                    {
                        extraBuffer = allocator.Invoke(newSize, false);
                        initialBuffer.CopyTo(extraBuffer.Memory.Span);
                        initialBuffer.Clear();
                    }
                    else if (newSize > extraBuffer.Length)
                    {
                        newBuffer = allocator.Invoke(newSize, false);
                        extraBuffer.Memory.CopyTo(newBuffer.Memory);
                        extraBuffer.Dispose();
                        extraBuffer = newBuffer;
                    }

                    output = extraBuffer.Memory.Span;
                }
                else
                {
                    output = initialBuffer;
                }

                offset = position;
            }
            else
            {
                // grow if needed
                if (newSize > initialBuffer.Length && newSize - initialBuffer.Length > extraBuffer.Length)
                {
                    newBuffer = allocator.Invoke(newSize, false);
                    extraBuffer.Memory.CopyTo(newBuffer.Memory);
                    extraBuffer.Dispose();
                    extraBuffer = newBuffer;
                }

                // append elements
                if (position < initialBuffer.Length)
                {
                    var writtenCount = Math.Min(initialBuffer.Length - position, input.Length);
                    input.Slice(0, writtenCount).CopyTo(initialBuffer.Slice(position));
                    input  = input.Slice(writtenCount);
                    offset = 0;
                }
                else
                {
                    offset = position - initialBuffer.Length;
                }

                output = extraBuffer.Memory.Span;
            }

            input.CopyTo(output.Slice(offset));
            position = newSize;
        }
Beispiel #26
0
 internal PooledMemoryChunk(MemoryAllocator <T>?allocator, int length, MemoryChunk?previous = null)
     : base(previous)
 {
     owner = allocator.Invoke(length, false);
 }
Beispiel #27
0
 internal void Realloc(MemoryAllocator <T>?allocator, int length)
 {
     owner.Dispose();
     owner = allocator.Invoke(length, false);
 }
Beispiel #28
0
 public static void DefaultValue()
 {
     using var owner = new MemoryOwner <decimal>();
     True(owner.IsEmpty);
     True(owner.Memory.IsEmpty);
 }
Beispiel #29
0
 public static void RentFromMemoryPoolDefaultSize()
 {
     using var owner = new MemoryOwner <byte>(MemoryPool <byte> .Shared);
     False(owner.Memory.IsEmpty);
 }
Beispiel #30
0
 internal static void Expand(ref MemoryOwner <T> owner)
 => Unsafe.AsRef(in owner.length) = owner.RealLength;