GtkSharp/Source/Libs/GLibSharp/PtrArray.cs

269 lines
7.5 KiB
C#

// PtrArray.cs - PtrArray wrapper implementation
//
// Authors: Mike Gorse <mgorse@novell.com>
//
// Copyright (c) 2008 Novell, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the Lesser GNU General
// Public License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
namespace GLib {
using System;
using System.Collections;
using System.Runtime.InteropServices;
public class PtrArray : IDisposable, ICollection, ICloneable, IWrapper {
private IntPtr handle = IntPtr.Zero;
private bool managed = false;
internal bool elements_owned = false;
protected System.Type element_type = null;
delegate IntPtr d_g_ptr_array_sized_new(uint n_preallocs);
static d_g_ptr_array_sized_new g_ptr_array_sized_new = FuncLoader.LoadFunction<d_g_ptr_array_sized_new>(FuncLoader.GetProcAddress(GLibrary.Load(Library.GObject), "g_ptr_array_sized_new"));
public PtrArray (uint n_preallocs, System.Type element_type, bool owned, bool elements_owned)
{
handle = g_ptr_array_sized_new (n_preallocs);
this.element_type = element_type;
managed = owned;
this.elements_owned = elements_owned;
}
delegate IntPtr d_g_ptr_array_new();
static d_g_ptr_array_new g_ptr_array_new = FuncLoader.LoadFunction<d_g_ptr_array_new>(FuncLoader.GetProcAddress(GLibrary.Load(Library.GObject), "g_ptr_array_new"));
public PtrArray (System.Type element_type, bool owned, bool elements_owned)
{
handle = g_ptr_array_new ();
this.element_type = element_type;
managed = owned;
this.elements_owned = elements_owned;
}
internal PtrArray (IntPtr raw, System.Type element_type, bool owned, bool elements_owned)
{
handle = raw;
this.element_type = element_type;
managed = owned;
this.elements_owned = elements_owned;
}
public PtrArray (IntPtr raw, System.Type element_type) : this (raw, element_type, false, false) {}
public PtrArray (IntPtr raw) : this (raw, null) {}
~PtrArray ()
{
Dispose (false);
}
// IDisposable
public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
delegate void d_g_ptr_array_free(IntPtr raw, bool free_seg);
static d_g_ptr_array_free g_ptr_array_free = FuncLoader.LoadFunction<d_g_ptr_array_free>(FuncLoader.GetProcAddress(GLibrary.Load(Library.GObject), "g_ptr_array_free"));
delegate void d_g_object_unref(IntPtr item);
static d_g_object_unref g_object_unref = FuncLoader.LoadFunction<d_g_object_unref>(FuncLoader.GetProcAddress(GLibrary.Load(Library.GLib), "g_object_unref"));
void Dispose (bool disposing)
{
if (Handle == IntPtr.Zero)
return;
if (elements_owned) {
int count = Count;
for (uint i = 0; i < count; i++)
if (typeof (GLib.Object).IsAssignableFrom (element_type))
g_object_unref (NthData (i));
else if (typeof (GLib.Opaque).IsAssignableFrom (element_type))
GLib.Opaque.GetOpaque (NthData (i), element_type, true).Dispose ();
else
Marshaller.Free (NthData (i));
}
if (managed)
g_ptr_array_free (Handle, true);
handle = IntPtr.Zero;
}
public IntPtr Handle {
get {
return handle;
}
}
public IntPtr ArrayPtr {
get {
return Marshal.ReadIntPtr (Handle);
}
}
delegate void d_g_ptr_array_add(IntPtr raw, IntPtr val);
static d_g_ptr_array_add g_ptr_array_add = FuncLoader.LoadFunction<d_g_ptr_array_add>(FuncLoader.GetProcAddress(GLibrary.Load(Library.GObject), "g_ptr_array_add"));
public void Add (IntPtr val)
{
g_ptr_array_add (Handle, val);
}
delegate void d_g_ptr_array_remove(IntPtr raw, IntPtr data);
static d_g_ptr_array_remove g_ptr_array_remove = FuncLoader.LoadFunction<d_g_ptr_array_remove>(FuncLoader.GetProcAddress(GLibrary.Load(Library.GObject), "g_ptr_array_remove"));
public void Remove (IntPtr data)
{
g_ptr_array_remove (Handle, data);
}
delegate void d_g_ptr_array_remove_range(IntPtr raw, uint index, uint length);
static d_g_ptr_array_remove_range g_ptr_array_remove_range = FuncLoader.LoadFunction<d_g_ptr_array_remove_range>(FuncLoader.GetProcAddress(GLibrary.Load(Library.GObject), "g_ptr_array_remove_range"));
public void RemoveRange (IntPtr data, uint index, uint length)
{
g_ptr_array_remove_range (Handle, index, length);
}
struct GPtrArray {
public IntPtr pdata;
public uint len;
}
// ICollection
public int Count {
get {
GPtrArray native = (GPtrArray) Marshal.PtrToStructure (Handle, typeof (GPtrArray));
return (int) native.len;
}
}
public object this [int index] {
get {
IntPtr data = NthData ((uint) index);
object ret = null;
ret = DataMarshal (data);
return ret;
}
}
internal object DataMarshal (IntPtr data)
{
object ret = null;
if (element_type != null) {
if (element_type == typeof (string))
ret = Marshaller.Utf8PtrToString (data);
else if (element_type == typeof (IntPtr))
ret = data;
else if (element_type.IsSubclassOf (typeof (GLib.Object)))
ret = GLib.Object.GetObject (data, false);
else if (element_type.IsSubclassOf (typeof (GLib.Opaque)))
ret = GLib.Opaque.GetOpaque (data, element_type, elements_owned);
else if (element_type == typeof (int))
ret = (int) data;
else if (element_type.IsValueType)
ret = Marshal.PtrToStructure (data, element_type);
else
ret = Activator.CreateInstance (element_type, new object[] {data});
} else if (Object.IsObject (data))
ret = GLib.Object.GetObject (data, false);
return ret;
}
internal IntPtr NthData (uint index)
{
return Marshal.ReadIntPtr (ArrayPtr, (int) index * IntPtr.Size);;
}
// Synchronization could be tricky here. Hmm.
public bool IsSynchronized {
get { return false; }
}
public object SyncRoot {
get { return null; }
}
public void CopyTo (Array array, int index)
{
if (array == null)
throw new ArgumentNullException ("Array can't be null.");
if (index < 0)
throw new ArgumentOutOfRangeException ("Index must be greater than 0.");
if (index + Count < array.Length)
throw new ArgumentException ("Array not large enough to copy into starting at index.");
for (int i = 0; i < Count; i++)
((IList) array) [index + i] = this [i];
}
private class ListEnumerator : IEnumerator
{
private int current = -1;
private PtrArray vals;
public ListEnumerator (PtrArray vals)
{
this.vals = vals;
}
public object Current {
get {
if (current == -1)
return null;
return vals [current];
}
}
public bool MoveNext ()
{
if (++current >= vals.Count) {
current = -1;
return false;
}
return true;
}
public void Reset ()
{
current = -1;
}
}
// IEnumerable
public IEnumerator GetEnumerator ()
{
return new ListEnumerator (this);
}
delegate IntPtr d_g_ptr_array_copy(IntPtr raw);
static d_g_ptr_array_copy g_ptr_array_copy = FuncLoader.LoadFunction<d_g_ptr_array_copy>(FuncLoader.GetProcAddress(GLibrary.Load(Library.GObject), "g_ptr_array_copy"));
// ICloneable
public object Clone ()
{
return new PtrArray (g_ptr_array_copy (Handle), element_type, false, false);
}
}
}