Browse Source

[SL.Core] Merge pull request SixLabors/Core#25 from SixLabors/af/allocator-error-handling

Throw better exceptions from MemoryAllocators
af/octree-no-pixelmap
James Jackson-South 7 years ago
committed by GitHub
parent
commit
a2284718b6
  1. 10
      src/SixLabors.Core/Memory/ArrayPoolMemoryAllocator.cs
  2. 5
      src/SixLabors.Core/Memory/SimpleGcMemoryAllocator.cs
  3. 23
      tests/SixLabors.Core.Tests/Memory/ArrayPoolMemoryAllocatorTests.cs
  4. 43
      tests/SixLabors.Core.Tests/Memory/SimpleGcMemoryAllocatorTests.cs
  5. 16
      tests/SixLabors.Core.Tests/Memory/SimpleGcMemoryManagerTests.cs

10
src/SixLabors.Core/Memory/ArrayPoolMemoryAllocator.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
@ -91,8 +92,15 @@ namespace SixLabors.Memory
/// <inheritdoc />
public override IMemoryOwner<T> Allocate<T>(int length, AllocationOptions options = AllocationOptions.None)
{
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
int itemSizeBytes = Unsafe.SizeOf<T>();
int bufferSizeInBytes = length * itemSizeBytes;
if (bufferSizeInBytes < 0)
{
throw new ArgumentOutOfRangeException(
nameof(length),
$"{nameof(ArrayPoolMemoryAllocator)} can not allocate {length} elements of {typeof(T).Name}.");
}
ArrayPool<byte> pool = this.GetArrayPool(bufferSizeInBytes);
byte[] byteArray = pool.Rent(bufferSizeInBytes);
@ -109,6 +117,8 @@ namespace SixLabors.Memory
/// <inheritdoc />
public override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None)
{
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
ArrayPool<byte> pool = this.GetArrayPool(length);
byte[] byteArray = pool.Rent(length);

5
src/SixLabors.Core/Memory/SimpleGcMemoryAllocator.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using SixLabors.Memory.Internals;
@ -14,12 +15,16 @@ namespace SixLabors.Memory
/// <inheritdoc />
public override IMemoryOwner<T> Allocate<T>(int length, AllocationOptions options = AllocationOptions.None)
{
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
return new BasicArrayBuffer<T>(new T[length]);
}
/// <inheritdoc />
public override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None)
{
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
return new BasicByteBuffer(new byte[length]);
}
}

23
tests/SixLabors.Core.Tests/Memory/ArrayPoolMemoryManagerTests.cs → tests/SixLabors.Core.Tests/Memory/ArrayPoolMemoryAllocatorTests.cs

@ -12,7 +12,7 @@ using Xunit;
namespace SixLabors.Memory.Tests
{
public class ArrayPoolMemoryManagerTests
public class ArrayPoolMemoryAllocatorTests
{
private const int MaxPooledBufferSizeInBytes = 2048;
@ -231,9 +231,28 @@ namespace SixLabors.Memory.Tests
private uint dummy;
}
[StructLayout(LayoutKind.Explicit, Size = MaxPooledBufferSizeInBytes / 5)]
private const int SizeOfLargeStruct = MaxPooledBufferSizeInBytes / 5;
[StructLayout(LayoutKind.Explicit, Size = SizeOfLargeStruct)]
private struct LargeStruct
{
}
[Theory]
[InlineData(-1)]
[InlineData((int.MaxValue / SizeOfLargeStruct) + 1)]
public void AllocateIncorrectAmount_ThrowsCorrect_ArgumentOutOfRangeException(int length)
{
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => this.MemoryAllocator.Allocate<LargeStruct>(length));
Assert.Equal("length", ex.ParamName);
}
[Theory]
[InlineData(-1)]
public void AllocateManagedByteBuffer_IncorrectAmount_ThrowsCorrect_ArgumentOutOfRangeException(int length)
{
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => this.MemoryAllocator.AllocateManagedByteBuffer(length));
Assert.Equal("length", ex.ParamName);
}
}
}

43
tests/SixLabors.Core.Tests/Memory/SimpleGcMemoryAllocatorTests.cs

@ -0,0 +1,43 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.InteropServices;
using Xunit;
namespace SixLabors.Memory.Tests
{
public class SimpleGcMemoryAllocatorTests
{
public class BufferTests : BufferTestSuite
{
public BufferTests()
: base(new SimpleGcMemoryAllocator())
{
}
}
protected SimpleGcMemoryAllocator MemoryAllocator { get; } = new SimpleGcMemoryAllocator();
[Theory]
[InlineData(-1)]
public void Allocate_IncorrectAmount_ThrowsCorrect_ArgumentOutOfRangeException(int length)
{
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => this.MemoryAllocator.Allocate<BigStruct>( length));
Assert.Equal("length", ex.ParamName);
}
[Theory]
[InlineData(-1)]
public void AllocateManagedByteBuffer_IncorrectAmount_ThrowsCorrect_ArgumentOutOfRangeException(int length)
{
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => this.MemoryAllocator.AllocateManagedByteBuffer(length));
Assert.Equal("length", ex.ParamName);
}
[StructLayout(LayoutKind.Explicit, Size = 512)]
private struct BigStruct
{
}
}
}

16
tests/SixLabors.Core.Tests/Memory/SimpleGcMemoryManagerTests.cs

@ -1,16 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.Memory.Tests
{
public class SimpleGcMemoryManagerTests
{
public class BufferTests : BufferTestSuite
{
public BufferTests()
: base(new SimpleGcMemoryAllocator())
{
}
}
}
}
Loading…
Cancel
Save