corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28 using System.Collections.Generic;
29 using System.Collections;
30  
31 namespace OpenMetaverse
32 {
33  
34 /// <summary>
35 ///
36 /// </summary>
37 public enum DictionaryEventAction
38 {
39 /// <summary>
40 ///
41 /// </summary>
42 Add,
43 /// <summary>
44 ///
45 /// </summary>
46 Remove,
47 /// <summary>
48 ///
49 /// </summary>
50 Change
51 }
52  
53 /// <summary>
54 ///
55 /// </summary>
56 /// <param name="action"></param>
57 /// <param name="entry"></param>
58 public delegate void DictionaryChangeCallback(DictionaryEventAction action, DictionaryEntry entry);
59  
60 /// <summary>
61 /// The ObservableDictionary class is used for storing key/value pairs. It has methods for firing
62 /// events to subscribers when items are added, removed, or changed.
63 /// </summary>
64 /// <typeparam name="TKey">Key <see langword="Tkey"/></typeparam>
65 /// <typeparam name="TValue">Value <see langword="TValue"/></typeparam>
66 public class ObservableDictionary<TKey, TValue>
67 {
68 #region Observable implementation
69 /// <summary>
70 /// A dictionary of callbacks to fire when specified action occurs
71 /// </summary>
72 private Dictionary<DictionaryEventAction, List<DictionaryChangeCallback>> Delegates;
73  
74 /// <summary>
75 /// Register a callback to be fired when an action occurs
76 /// </summary>
77 /// <param name="action">The action</param>
78 /// <param name="callback">The callback to fire</param>
79 public void AddDelegate(DictionaryEventAction action, DictionaryChangeCallback callback)
80 {
81 if (Delegates.ContainsKey(action))
82 {
83 Delegates[action].Add(callback);
84 }
85 else
86 {
87 List<DictionaryChangeCallback> callbacks = new List<DictionaryChangeCallback>(1);
88 callbacks.Add(callback);
89 Delegates.Add(action, callbacks);
90 }
91 }
92  
93 /// <summary>
94 /// Unregister a callback
95 /// </summary>
96 /// <param name="action">The action</param>
97 /// <param name="callback">The callback to fire</param>
98 public void RemoveDelegate(DictionaryEventAction action, DictionaryChangeCallback callback)
99 {
100 if (Delegates.ContainsKey(action))
101 {
102 if (Delegates[action].Contains(callback))
103 Delegates[action].Remove(callback);
104 }
105 }
106  
107 /// <summary>
108 ///
109 /// </summary>
110 /// <param name="action"></param>
111 /// <param name="entry"></param>
112 private void FireChangeEvent(DictionaryEventAction action, DictionaryEntry entry)
113 {
114  
115 if(Delegates.ContainsKey(action))
116 {
117 foreach(DictionaryChangeCallback handler in Delegates[action])
118 {
119 handler(action, entry);
120 }
121 }
122 }
123  
124 #endregion
125  
126 /// <summary>Internal dictionary that this class wraps around. Do not
127 /// modify or enumerate the contents of this dictionary without locking</summary>
128 private Dictionary<TKey, TValue> Dictionary;
129  
130 /// <summary>
131 /// Gets the number of Key/Value pairs contained in the <seealso cref="T:ObservableDictionary"/>
132 /// </summary>
133 public int Count { get { return Dictionary.Count; } }
134  
135 /// <summary>
136 /// Initializes a new instance of the <seealso cref="T:ObservableDictionary"/> Class
137 /// with the specified key/value, has the default initial capacity.
138 /// </summary>
139 /// <example>
140 /// <code>
141 /// // initialize a new ObservableDictionary named testDict with a string as the key and an int as the value.
142 /// public ObservableDictionary&lt;string, int&gt; testDict = new ObservableDictionary&lt;string, int&gt;();
143 /// </code>
144 /// </example>
145 public ObservableDictionary()
146 {
147 Dictionary = new Dictionary<TKey, TValue>();
148 Delegates = new Dictionary<DictionaryEventAction, List<DictionaryChangeCallback>>();
149 }
150  
151 /// <summary>
152 /// Initializes a new instance of the <seealso cref="T:OpenMetaverse.ObservableDictionary"/> Class
153 /// with the specified key/value, With its initial capacity specified.
154 /// </summary>
155 /// <param name="capacity">Initial size of dictionary</param>
156 /// <example>
157 /// <code>
158 /// // initialize a new ObservableDictionary named testDict with a string as the key and an int as the value,
159 /// // initially allocated room for 10 entries.
160 /// public ObservableDictionary&lt;string, int&gt; testDict = new ObservableDictionary&lt;string, int&gt;(10);
161 /// </code>
162 /// </example>
163 public ObservableDictionary(int capacity)
164 {
165 Dictionary = new Dictionary<TKey, TValue>(capacity);
166 Delegates = new Dictionary<DictionaryEventAction, List<DictionaryChangeCallback>>();
167 }
168  
169 /// <summary>
170 /// Try to get entry from the <seealso cref="ObservableDictionary"/> with specified key
171 /// </summary>
172 /// <param name="key">Key to use for lookup</param>
173 /// <param name="value">Value returned</param>
174 /// <returns><see langword="true"/> if specified key exists, <see langword="false"/> if not found</returns>
175 /// <example>
176 /// <code>
177 /// // find your avatar using the Simulator.ObjectsAvatars ObservableDictionary:
178 /// Avatar av;
179 /// if (Client.Network.CurrentSim.ObjectsAvatars.TryGetValue(Client.Self.AgentID, out av))
180 /// Console.WriteLine("Found Avatar {0}", av.Name);
181 /// </code>
182 /// <seealso cref="Simulator.ObjectsAvatars"/>
183 /// </example>
184 public bool TryGetValue(TKey key, out TValue value)
185 {
186 return Dictionary.TryGetValue(key, out value);
187 }
188  
189 /// <summary>
190 /// Finds the specified match.
191 /// </summary>
192 /// <param name="match">The match.</param>
193 /// <returns>Matched value</returns>
194 /// <example>
195 /// <code>
196 /// // use a delegate to find a prim in the ObjectsPrimitives ObservableDictionary
197 /// // with the ID 95683496
198 /// uint findID = 95683496;
199 /// Primitive findPrim = sim.ObjectsPrimitives.Find(
200 /// delegate(Primitive prim) { return prim.ID == findID; });
201 /// </code>
202 /// </example>
203 public TValue Find(Predicate<TValue> match)
204 {
205 foreach (TValue value in Dictionary.Values)
206 {
207 if (match(value))
208 return value;
209 }
210 return default(TValue);
211 }
212  
213 /// <summary>Find All items in an <seealso cref="T:ObservableDictionary"/></summary>
214 /// <param name="match">return matching items.</param>
215 /// <returns>a <seealso cref="T:System.Collections.Generic.List"/> containing found items.</returns>
216 /// <example>
217 /// Find All prims within 20 meters and store them in a List
218 /// <code>
219 /// int radius = 20;
220 /// List&lt;Primitive&gt; prims = Client.Network.CurrentSim.ObjectsPrimitives.FindAll(
221 /// delegate(Primitive prim) {
222 /// Vector3 pos = prim.Position;
223 /// return ((prim.ParentID == 0) &amp;&amp; (pos != Vector3.Zero) &amp;&amp; (Vector3.Distance(pos, location) &lt; radius));
224 /// }
225 /// );
226 ///</code>
227 ///</example>
228 public List<TValue> FindAll(Predicate<TValue> match)
229 {
230 List<TValue> found = new List<TValue>();
231  
232 foreach (KeyValuePair<TKey, TValue> kvp in Dictionary)
233 {
234 if (match(kvp.Value))
235 found.Add(kvp.Value);
236 }
237 return found;
238 }
239  
240 /// <summary>Find All items in an <seealso cref="T:ObservableDictionary"/></summary>
241 /// <param name="match">return matching keys.</param>
242 /// <returns>a <seealso cref="T:System.Collections.Generic.List"/> containing found keys.</returns>
243 /// <example>
244 /// Find All keys which also exist in another dictionary
245 /// <code>
246 /// List&lt;UUID&gt; matches = myDict.FindAll(
247 /// delegate(UUID id) {
248 /// return myOtherDict.ContainsKey(id);
249 /// }
250 /// );
251 ///</code>
252 ///</example>
253 public List<TKey> FindAll(Predicate<TKey> match)
254 {
255 List<TKey> found = new List<TKey>();
256  
257 foreach (KeyValuePair<TKey, TValue> kvp in Dictionary)
258 {
259 if (match(kvp.Key))
260 found.Add(kvp.Key);
261 }
262  
263 return found;
264 }
265  
266 /// <summary>Check if Key exists in Dictionary</summary>
267 /// <param name="key">Key to check for</param>
268 /// <returns><see langword="true"/> if found, <see langword="false"/> otherwise</returns>
269 public bool ContainsKey(TKey key)
270 {
271 return Dictionary.ContainsKey(key);
272 }
273  
274 /// <summary>Check if Value exists in Dictionary</summary>
275 /// <param name="value">Value to check for</param>
276 /// <returns><see langword="true"/> if found, <see langword="false"/> otherwise</returns>
277 public bool ContainsValue(TValue value)
278 {
279 return Dictionary.ContainsValue(value);
280 }
281  
282 /// <summary>
283 /// Adds the specified key to the dictionary, dictionary locking is not performed,
284 /// <see cref="SafeAdd"/>
285 /// </summary>
286 /// <param name="key">The key</param>
287 /// <param name="value">The value</param>
288 public void Add(TKey key, TValue value)
289 {
290 Dictionary.Add(key, value);
291 FireChangeEvent(DictionaryEventAction.Add, new DictionaryEntry(key, value));
292 }
293  
294 /// <summary>
295 /// Removes the specified key, dictionary locking is not performed
296 /// </summary>
297 /// <param name="key">The key.</param>
298 /// <returns><see langword="true"/> if successful, <see langword="false"/> otherwise</returns>
299 public bool Remove(TKey key)
300 {
301 FireChangeEvent(DictionaryEventAction.Remove, new DictionaryEntry(key, Dictionary[key]));
302 return Dictionary.Remove(key);
303 }
304  
305 /// <summary>
306 /// Indexer for the dictionary
307 /// </summary>
308 /// <param name="key">The key</param>
309 /// <returns>The value</returns>
310 public TValue this[TKey key]
311 {
312 get { return Dictionary[key]; }
313 set { FireChangeEvent(DictionaryEventAction.Add, new DictionaryEntry(key, value));
314 Dictionary[key] = value; }
315 }
316  
317 /// <summary>
318 /// Clear the contents of the dictionary
319 /// </summary>
320 public void Clear()
321 {
322 foreach (KeyValuePair<TKey, TValue> kvp in Dictionary)
323 FireChangeEvent(DictionaryEventAction.Remove, new DictionaryEntry(kvp.Key, kvp.Value));
324  
325 Dictionary.Clear();
326 }
327  
328 /// <summary>
329 /// Enumerator for iterating dictionary entries
330 /// </summary>
331 /// <returns></returns>
332 public System.Collections.IEnumerator GetEnumerator()
333 {
334 return Dictionary.GetEnumerator();
335 }
336 }
337 }