//-----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation.
//
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop.Implementation
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
///
/// A collection of GCHandles for pinned objects. The handles
/// are freed when this object is disposed.
///
[StructLayout(LayoutKind.Auto)]
internal struct GCHandleCollection : IDisposable
{
///
/// The handles of the objects being pinned.
///
private GCHandle[] handles;
///
/// Handle count.
///
private int count;
///
/// Disposes of the object.
///
public void Dispose()
{
if (null != this.handles)
{
for (int i = 0; i < this.count; i++)
{
this.handles[i].Free();
}
this.handles = null;
}
}
///
/// Add an object to the handle collection. This automatically
/// pins the object.
///
/// The object to pin.
///
/// The address of the pinned object. This is valid until the
/// GCHandleCollection is disposed.
///
public IntPtr Add(object value)
{
if (null == value)
{
return IntPtr.Zero;
}
if (null == this.handles)
{
this.handles = new GCHandle[4]; // same as List
}
else if (this.count == this.handles.Length)
{
Array.Resize(ref this.handles, this.count * 2);
}
Debug.Assert(this.count < this.handles.Length, "Index out of bound");
GCHandle handle = GCHandle.Alloc(value, GCHandleType.Pinned);
this.handles[this.count++] = handle;
IntPtr pinned = handle.AddrOfPinnedObject();
Debug.Assert(IntPtr.Zero != pinned, "Pinned object has null address");
return pinned;
}
///
/// Set handle array capacity.
///
/// Estimated handle count
public void SetCapacity(int capacity)
{
if (null == this.handles)
{
this.handles = new GCHandle[capacity];
}
}
}
}