1 // ValueArray.cs - ValueArray wrapper implementation
2 //
3 // Authors: Mike Kestner <mkestner@ximian.com>
4 //
5 // Copyright (c) 2003 Novell, Inc.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of version 2 of the Lesser GNU General
9 // Public License as published by the Free Software Foundation.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this program; if not, write to the
18 // Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 // Boston, MA 02111-1307, USA.
20 
21 
22 namespace GLib {
23 
24 	using System;
25 	using System.Collections;
26 	using System.Collections.Generic;
27 	using System.Runtime.InteropServices;
28 
29 	public class ValueArray : IDisposable, ICollection, ICloneable, IWrapper {
30 
31 		private IntPtr handle = IntPtr.Zero;
32 
33 		static private IList<IntPtr> PendingFrees = new List<IntPtr> ();
34 		static private bool idle_queued = false;
35 
36 		[DllImport (Global.GObjectNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_value_array_new(uint n_preallocs)37 		static extern IntPtr g_value_array_new (uint n_preallocs);
38 
ValueArray(uint n_preallocs)39 		public ValueArray (uint n_preallocs)
40 		{
41 			handle = g_value_array_new (n_preallocs);
42 		}
43 
ValueArray(IntPtr raw)44 		public ValueArray (IntPtr raw)
45 		{
46 			handle = raw;
47 		}
48 
~ValueArray()49 		~ValueArray ()
50 		{
51 			Dispose (false);
52 		}
53 
54 		// IDisposable
Dispose()55 		public void Dispose ()
56 		{
57 			Dispose (true);
58 			GC.SuppressFinalize (this);
59 		}
60 
61 		[DllImport (Global.GObjectNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_value_array_free(IntPtr raw)62 		static extern void g_value_array_free (IntPtr raw);
63 
Dispose(bool disposing)64 		void Dispose (bool disposing)
65 		{
66 			if (Handle == IntPtr.Zero)
67 				return;
68 
69 			lock (PendingFrees) {
70 				PendingFrees.Add (handle);
71 
72 				if (! idle_queued) {
73 					Timeout.Add (50, new TimeoutHandler (PerformFrees));
74 					idle_queued = true;
75 				}
76 			}
77 
78 			handle = IntPtr.Zero;
79 		}
80 
PerformFrees()81 		static bool PerformFrees ()
82 		{
83 			IntPtr[] handles;
84 
85 			lock (PendingFrees) {
86 				idle_queued = false;
87 
88 				handles = new IntPtr [PendingFrees.Count];
89 				PendingFrees.CopyTo (handles, 0);
90 				PendingFrees.Clear ();
91 			}
92 
93 			foreach (IntPtr h in handles)
94 				g_value_array_free (h);
95 
96 			return false;
97 		}
98 
99 		public IntPtr Handle {
100 			get {
101 				return handle;
102 			}
103 		}
104 
105 		struct NativeStruct {
106 			public uint n_values;
107 			public IntPtr values;
108 			public uint n_prealloced;
109 		}
110 
111 		NativeStruct Native {
112 			get { return (NativeStruct) Marshal.PtrToStructure (Handle, typeof(NativeStruct)); }
113 		}
114 
115 		public IntPtr ArrayPtr {
116 			get { return Native.values; }
117 		}
118 
119 		[DllImport (Global.GObjectNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_value_array_append(IntPtr raw, ref GLib.Value val)120 		static extern void g_value_array_append (IntPtr raw, ref GLib.Value val);
121 
Append(GLib.Value val)122 		public void Append (GLib.Value val)
123 		{
124 			g_value_array_append (Handle, ref val);
125 		}
126 
127 		[DllImport (Global.GObjectNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_value_array_insert(IntPtr raw, uint idx, ref GLib.Value val)128 		static extern void g_value_array_insert (IntPtr raw, uint idx, ref GLib.Value val);
129 
Insert(uint idx, GLib.Value val)130 		public void Insert (uint idx, GLib.Value val)
131 		{
132 			g_value_array_insert (Handle, idx, ref val);
133 		}
134 
135 		[DllImport (Global.GObjectNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_value_array_prepend(IntPtr raw, ref GLib.Value val)136 		static extern void g_value_array_prepend (IntPtr raw, ref GLib.Value val);
137 
Prepend(GLib.Value val)138 		public void Prepend (GLib.Value val)
139 		{
140 			g_value_array_prepend (Handle, ref val);
141 		}
142 
143 		[DllImport (Global.GObjectNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_value_array_remove(IntPtr raw, uint idx)144 		static extern void g_value_array_remove (IntPtr raw, uint idx);
145 
Remove(uint idx)146 		public void Remove (uint idx)
147 		{
148 			g_value_array_remove (Handle, idx);
149 		}
150 
151 		// ICollection
152 		public int Count {
153 			get { return (int) Native.n_values; }
154 		}
155 
156 		[DllImport (Global.GObjectNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_value_array_get_nth(IntPtr raw, uint idx)157 		static extern IntPtr g_value_array_get_nth (IntPtr raw, uint idx);
158 
159 		public object this [int index] {
160 			get {
161 				IntPtr raw_val = g_value_array_get_nth (Handle, (uint) index);
162 				return Marshal.PtrToStructure (raw_val, typeof (GLib.Value));
163 			}
164 		}
165 
166 		// Synchronization could be tricky here. Hmm.
167 		public bool IsSynchronized {
168 			get { return false; }
169 		}
170 
171 		public object SyncRoot {
172 			get { return null; }
173 		}
174 
CopyTo(Array array, int index)175 		public void CopyTo (Array array, int index)
176 		{
177 			if (array == null)
178 				throw new ArgumentNullException ("Array can't be null.");
179 
180 			if (index < 0)
181 				throw new ArgumentOutOfRangeException ("Index must be greater than 0.");
182 
183 			if (index + Count < array.Length)
184 				throw new ArgumentException ("Array not large enough to copy into starting at index.");
185 
186 			for (int i = 0; i < Count; i++)
187 				((IList) array) [index + i] = this [i];
188 		}
189 
190 		private class ListEnumerator : IEnumerator
191 		{
192 			private int current = -1;
193 			private ValueArray vals;
194 
ListEnumerator(ValueArray vals)195 			public ListEnumerator (ValueArray vals)
196 			{
197 				this.vals = vals;
198 			}
199 
200 			public object Current {
201 				get {
202 					if (current == -1)
203 						return null;
204 					return vals [current];
205 				}
206 			}
207 
MoveNext()208 			public bool MoveNext ()
209 			{
210 				if (++current >= vals.Count) {
211 					current = -1;
212 					return false;
213 				}
214 
215 				return true;
216 			}
217 
Reset()218 			public void Reset ()
219 			{
220 				current = -1;
221 			}
222 		}
223 
224 		// IEnumerable
GetEnumerator()225 		public IEnumerator GetEnumerator ()
226 		{
227 			return new ListEnumerator (this);
228 		}
229 
230 		[DllImport (Global.GObjectNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_value_array_copy(IntPtr raw)231 		static extern IntPtr g_value_array_copy (IntPtr raw);
232 
233 		// ICloneable
Clone()234 		public object Clone ()
235 		{
236 			return new ValueArray (g_value_array_copy (Handle));
237 		}
238 
239 		[DllImport (Global.GObjectNativeDll, CallingConvention = CallingConvention.Cdecl)]
g_value_array_get_type()240 		static extern IntPtr g_value_array_get_type ();
241 
242 		public static GLib.GType GType {
243 			get {
244 				return new GLib.GType (g_value_array_get_type ());
245 			}
246 		}
247 	}
248 }
249