Files
DotNetAlpm/Alpm/CollectionWrapper`2.cs
2020-04-29 13:21:13 -04:00

131 lines
3.9 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
// FIXME: This is increasing the ref-count on AlpmHandle all the time, so this is NOT correct for database handles,
// or other handles that have a dispose that is not a no-op.
namespace Foodsoft.Alpm
{
internal class CollectionWrapper<TImpl, TElement> : ICollection<TElement> where TImpl : struct,
IItemsAccessor<TElement>
{
private TImpl _impl;
public CollectionWrapper(TImpl impl)
{
_impl = impl;
}
private static unsafe IntPtr ListNext(IntPtr list) => ((alpm_list_t*) list)->next;
private static unsafe IntPtr ListData(IntPtr list) => ((alpm_list_t*) list)->data;
public IEnumerator<TElement> GetEnumerator()
{
var safeAlpmHandle = _impl.SafeAlpmHandle;
var release = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
safeAlpmHandle.DangerousAddRef(ref release);
if (!release) throw new ObjectDisposedException(_impl.GetType().FullName);
for (var list = _impl.GetItems(); list != IntPtr.Zero; list = ListNext(list))
{
yield return _impl.PtrToItem(ListData(list));
}
}
finally
{
if (release)
safeAlpmHandle.DangerousRelease();
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public void Add(TElement item)
{
_impl.AddItem(item);
}
public void Clear()
{
_impl.SetItems(IntPtr.Zero);
}
public bool Contains(TElement item)
{
var safeAlpmHandle = _impl.SafeAlpmHandle;
var release = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
safeAlpmHandle.DangerousAddRef(ref release);
return _impl.FindItem(item) != IntPtr.Zero;
}
finally
{
if (release)
safeAlpmHandle.DangerousRelease();
}
}
public void CopyTo(TElement[] array, int arrayIndex)
{
var safeAlpmHandle = _impl.SafeAlpmHandle;
var release = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
safeAlpmHandle.DangerousAddRef(ref release);
var intPtr = _impl.GetItems();
unsafe
{
for (var list = (alpm_list_t*) intPtr; list != null; list = alpm.alpm_list_next(list))
{
array[arrayIndex++] = _impl.PtrToItem(list->data);
}
}
}
finally
{
if (release)
safeAlpmHandle.DangerousRelease();
}
}
public bool Remove(TElement item)
{
var err = _impl.RemoveItem(item);
if (err < 0)
{
throw new Exception(alpm.alpm_errno(_impl.SafeAlpmHandle));
}
return err == 0;
}
public int Count
{
get
{
var safeAlpmHandle = _impl.SafeAlpmHandle;
var release = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
safeAlpmHandle.DangerousAddRef(ref release);
return (int) alpm.alpm_list_count(_impl.GetItems());
}
finally
{
if (release)
safeAlpmHandle.DangerousRelease();
}
}
}
public bool IsReadOnly => false;
}
}