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