1 /* 2 * Copyright (c) 2010 Nathaniel McCallum <nathaniel@natemccallum.com> 3 * 4 * The code contained in this file is free software; you can redistribute 5 * it and/or modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either version 7 * 2.1 of the License, or (at your option) any later version. 8 * 9 * This file is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this code; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19 namespace GPod { 20 using System; 21 using System.Collections; 22 using System.Collections.Generic; 23 using System.Linq; 24 using System.Runtime.InteropServices; 25 using GLib; 26 27 internal abstract class GPodList<T> : IList<T> where T : IGPodBase { 28 29 protected HandleRef handle; 30 protected abstract GLib.List List { 31 get; 32 } 33 protected bool owner; 34 GPodList(bool owner, HandleRef handle, List list)35 public GPodList(bool owner, HandleRef handle, List list) { this.handle = handle; this.owner = owner; } GPodList(HandleRef handle, List list)36 public GPodList(HandleRef handle, List list) : this(false, handle, list) {} GPodList(bool owner, HandleRef handle, IntPtr listp)37 public GPodList(bool owner, HandleRef handle, IntPtr listp) : this(owner, handle, null) {} GPodList(HandleRef handle, IntPtr listp)38 public GPodList(HandleRef handle, IntPtr listp) : this(false, handle, listp) {} 39 40 public int Count { get { return List.Count; } } 41 public bool IsReadOnly { get { return false; } } 42 public T this[int index] { get { return (T) List[index]; } 43 set { RemoveAt(index); Insert(index, value); } } 44 Add(T item)45 public void Add(T item) { DoAdd (-1, item); if (owner) item.SetBorrowed(true); } Clear()46 public void Clear() { /* Ensure we invoke DoUnlink */ while (Count > 0) RemoveAt (0); } CopyTo(T[] array, int arrayIndex)47 public void CopyTo(T[] array, int arrayIndex) { List.CopyTo(array, arrayIndex); } GetEnumerator()48 public IEnumerator<T> GetEnumerator() { 49 // Make an explicit copy of the list here to avoid memory 50 // corruption issues. What was happening is that managed land was 51 // instantiating a GLib.List from the native pointer, then if an 52 // item was unlinked from the native list, the GList in managed 53 // land would now be pointing at freed memory and would randomly 54 // blow up or crash. We work around this by instantiating a 55 // GLib.List every time and copying everything out immediately. 56 foreach (T t in List.Cast<T> ().ToArray ()) 57 yield return t; 58 } IEnumerable.GetEnumerator()59 IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } 60 Contains(T item)61 public bool Contains(T item) { 62 return IndexOf(item) != -1; 63 } 64 IndexOf(T item)65 public int IndexOf(T item) { 66 int i = 0; 67 foreach (T t in this) { 68 if (object.ReferenceEquals(t, item) || t.Native == item.Native) 69 return i; 70 i++; 71 } 72 return -1; 73 } 74 Remove(T item)75 public bool Remove(T item) { 76 int index = IndexOf(item); 77 if (index < 0) return false; 78 RemoveAt(index); 79 return true; 80 } 81 Insert(int index, T item)82 public void Insert(int index, T item) { 83 if (owner) item.SetBorrowed(true); 84 DoAdd(index, item); 85 } 86 RemoveAt(int index)87 public void RemoveAt(int index) { 88 if (owner) this[index].SetBorrowed(false); 89 DoUnlink(index); 90 } 91 DoAdd(int index, T item)92 protected abstract void DoAdd(int index, T item); DoUnlink(int index)93 protected abstract void DoUnlink(int index); 94 } 95 } 96