mirror of https://github.com/SixLabors/ImageSharp
committed by
GitHub
21 changed files with 553 additions and 81 deletions
@ -0,0 +1,61 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Buffers; |
|||
|
|||
namespace SixLabors.ImageSharp.Memory; |
|||
|
|||
/// <summary>
|
|||
/// Provides the tracked memory-owner contract required by <see cref="MemoryAllocator"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The element type.</typeparam>
|
|||
/// <remarks>
|
|||
/// Custom allocators implement <see cref="MemoryAllocator.AllocateCore{T}(int, AllocationOptions)"/>
|
|||
/// and return a derived type. The base allocator attaches allocation tracking after the owner has been
|
|||
/// created so custom implementations cannot forget, duplicate, or mismatch the reservation lifecycle.
|
|||
/// </remarks>
|
|||
public abstract class AllocationTrackedMemoryManager<T> : MemoryManager<T> |
|||
where T : struct |
|||
{ |
|||
private AllocationTrackingState allocationTracking; |
|||
|
|||
/// <summary>
|
|||
/// Releases resources held by the concrete tracked owner.
|
|||
/// </summary>
|
|||
/// <param name="disposing">
|
|||
/// <see langword="true"/> when the owner is being disposed deterministically;
|
|||
/// otherwise, <see langword="false"/>.
|
|||
/// </param>
|
|||
/// <remarks>
|
|||
/// Implementations release their own resources here. Allocation tracking is released by the sealed base
|
|||
/// dispose path after this method returns.
|
|||
/// </remarks>
|
|||
protected abstract void DisposeCore(bool disposing); |
|||
|
|||
/// <inheritdoc />
|
|||
protected sealed override void Dispose(bool disposing) |
|||
{ |
|||
this.DisposeCore(disposing); |
|||
this.ReleaseAllocationTracking(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Attaches allocation tracking to this owner after allocation has succeeded.
|
|||
/// </summary>
|
|||
/// <param name="allocator">The allocator that owns the reservation for this instance.</param>
|
|||
/// <param name="lengthInBytes">The reserved allocation size, in bytes.</param>
|
|||
/// <remarks>
|
|||
/// <see cref="MemoryAllocator"/> calls this exactly once after <c>AllocateCore</c> returns.
|
|||
/// Derived allocators should not call it themselves; they only construct the concrete owner.
|
|||
/// </remarks>
|
|||
internal void AttachAllocationTracking(MemoryAllocator allocator, long lengthInBytes) |
|||
=> this.allocationTracking.Attach(allocator, lengthInBytes); |
|||
|
|||
/// <summary>
|
|||
/// Releases any tracked allocation bytes associated with this instance.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Calling this more than once is safe; only the first call after tracking has been attached releases bytes.
|
|||
/// </remarks>
|
|||
private void ReleaseAllocationTracking() => this.allocationTracking.Release(); |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Memory; |
|||
|
|||
/// <summary>
|
|||
/// Tracks a single allocator reservation and releases it exactly once.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This type is intended to live as a mutable field on the owning object. It should not be copied
|
|||
/// after tracking has been attached, because the owner relies on a single shared release state.
|
|||
/// </remarks>
|
|||
internal struct AllocationTrackingState |
|||
{ |
|||
private MemoryAllocator? allocator; |
|||
private long lengthInBytes; |
|||
private int released; |
|||
|
|||
/// <summary>
|
|||
/// Attaches allocator reservation tracking to the current owner.
|
|||
/// </summary>
|
|||
/// <param name="allocator">The allocator that owns the reservation.</param>
|
|||
/// <param name="lengthInBytes">The reserved allocation size, in bytes.</param>
|
|||
internal void Attach(MemoryAllocator allocator, long lengthInBytes) |
|||
{ |
|||
this.allocator = allocator; |
|||
this.lengthInBytes = lengthInBytes; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Releases the attached allocator reservation once.
|
|||
/// </summary>
|
|||
internal void Release() |
|||
{ |
|||
if (Interlocked.Exchange(ref this.released, 1) == 0 && this.allocator != null) |
|||
{ |
|||
this.allocator.ReleaseAccumulatedBytes(this.lengthInBytes); |
|||
this.allocator = null; |
|||
} |
|||
} |
|||
} |
|||
@ -1,9 +1,19 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Memory; |
|||
|
|||
/// <summary>
|
|||
/// Provides helper methods for working with <see cref="AllocationOptions"/>.
|
|||
/// </summary>
|
|||
internal static class AllocationOptionsExtensions |
|||
{ |
|||
public static bool Has(this AllocationOptions options, AllocationOptions flag) => (options & flag) == flag; |
|||
/// <summary>
|
|||
/// Returns a value indicating whether the specified flag is set on the allocation options.
|
|||
/// </summary>
|
|||
/// <param name="options">The allocation options to inspect.</param>
|
|||
/// <param name="flag">The flag to test for.</param>
|
|||
/// <returns><see langword="true"/> if <paramref name="flag"/> is set; otherwise, <see langword="false"/>.</returns>
|
|||
public static bool Has(this AllocationOptions options, AllocationOptions flag) |
|||
=> (options & flag) == flag; |
|||
} |
|||
|
|||
Loading…
Reference in new issue