All files
[pithos-ms-client] / trunk / Libraries / Json40r2 / Source / Src / Newtonsoft.Json / Utilities / CollectionUtils.cs
1 #region License
2 // Copyright (c) 2007 James Newton-King
3 //
4 // Permission is hereby granted, free of charge, to any person
5 // obtaining a copy of this software and associated documentation
6 // files (the "Software"), to deal in the Software without
7 // restriction, including without limitation the rights to use,
8 // copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following
11 // conditions:
12 //
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 // OTHER DEALINGS IN THE SOFTWARE.
24 #endregion
25
26 using System;
27 using System.Collections.Generic;
28 using System.Collections.ObjectModel;
29 using System.Reflection;
30 using System.Text;
31 using System.Collections;
32 using System.Linq;
33 using System.Globalization;
34
35 namespace Newtonsoft.Json.Utilities
36 {
37   internal static class CollectionUtils
38   {
39     public static IEnumerable<T> CastValid<T>(this IEnumerable enumerable)
40     {
41       ValidationUtils.ArgumentNotNull(enumerable, "enumerable");
42
43       return enumerable.Cast<object>().Where(o => o is T).Cast<T>();
44     }
45
46     public static List<T> CreateList<T>(params T[] values)
47     {
48       return new List<T>(values);
49     }
50
51     /// <summary>
52     /// Determines whether the collection is null or empty.
53     /// </summary>
54     /// <param name="collection">The collection.</param>
55     /// <returns>
56     ///         <c>true</c> if the collection is null or empty; otherwise, <c>false</c>.
57     /// </returns>
58     public static bool IsNullOrEmpty(ICollection collection)
59     {
60       if (collection != null)
61       {
62         return (collection.Count == 0);
63       }
64       return true;
65     }
66
67     /// <summary>
68     /// Determines whether the collection is null or empty.
69     /// </summary>
70     /// <param name="collection">The collection.</param>
71     /// <returns>
72     ///         <c>true</c> if the collection is null or empty; otherwise, <c>false</c>.
73     /// </returns>
74     public static bool IsNullOrEmpty<T>(ICollection<T> collection)
75     {
76       if (collection != null)
77       {
78         return (collection.Count == 0);
79       }
80       return true;
81     }
82
83     /// <summary>
84     /// Determines whether the collection is null, empty or its contents are uninitialized values.
85     /// </summary>
86     /// <param name="list">The list.</param>
87     /// <returns>
88     ///         <c>true</c> if the collection is null or empty or its contents are uninitialized values; otherwise, <c>false</c>.
89     /// </returns>
90     public static bool IsNullOrEmptyOrDefault<T>(IList<T> list)
91     {
92       if (IsNullOrEmpty<T>(list))
93         return true;
94
95       return ReflectionUtils.ItemsUnitializedValue<T>(list);
96     }
97
98     /// <summary>
99     /// Makes a slice of the specified list in between the start and end indexes.
100     /// </summary>
101     /// <param name="list">The list.</param>
102     /// <param name="start">The start index.</param>
103     /// <param name="end">The end index.</param>
104     /// <returns>A slice of the list.</returns>
105     public static IList<T> Slice<T>(IList<T> list, int? start, int? end)
106     {
107       return Slice<T>(list, start, end, null);
108     }
109
110     /// <summary>
111     /// Makes a slice of the specified list in between the start and end indexes,
112     /// getting every so many items based upon the step.
113     /// </summary>
114     /// <param name="list">The list.</param>
115     /// <param name="start">The start index.</param>
116     /// <param name="end">The end index.</param>
117     /// <param name="step">The step.</param>
118     /// <returns>A slice of the list.</returns>
119     public static IList<T> Slice<T>(IList<T> list, int? start, int? end, int? step)
120     {
121       if (list == null)
122         throw new ArgumentNullException("list");
123
124       if (step == 0)
125         throw new ArgumentException("Step cannot be zero.", "step");
126
127       List<T> slicedList = new List<T>();
128
129       // nothing to slice
130       if (list.Count == 0)
131         return slicedList;
132
133       // set defaults for null arguments
134       int s = step ?? 1;
135       int startIndex = start ?? 0;
136       int endIndex = end ?? list.Count;
137
138       // start from the end of the list if start is negitive
139       startIndex = (startIndex < 0) ? list.Count + startIndex : startIndex;
140
141       // end from the start of the list if end is negitive
142       endIndex = (endIndex < 0) ? list.Count + endIndex : endIndex;
143
144       // ensure indexes keep within collection bounds
145       startIndex = Math.Max(startIndex, 0);
146       endIndex = Math.Min(endIndex, list.Count - 1);
147
148       // loop between start and end indexes, incrementing by the step
149       for (int i = startIndex; i < endIndex; i += s)
150       {
151         slicedList.Add(list[i]);
152       }
153
154       return slicedList;
155     }
156
157
158     /// <summary>
159     /// Group the collection using a function which returns the key.
160     /// </summary>
161     /// <param name="source">The source collection to group.</param>
162     /// <param name="keySelector">The key selector.</param>
163     /// <returns>A Dictionary with each key relating to a list of objects in a list grouped under it.</returns>
164     public static Dictionary<K, List<V>> GroupBy<K, V>(ICollection<V> source, Func<V, K> keySelector)
165     {
166       if (keySelector == null)
167         throw new ArgumentNullException("keySelector");
168
169       Dictionary<K, List<V>> groupedValues = new Dictionary<K, List<V>>();
170
171       foreach (V value in source)
172       {
173         // using delegate to get the value's key
174         K key = keySelector(value);
175         List<V> groupedValueList;
176
177         // add a list for grouped values if the key is not already in Dictionary
178         if (!groupedValues.TryGetValue(key, out groupedValueList))
179         {
180           groupedValueList = new List<V>();
181           groupedValues.Add(key, groupedValueList);
182         }
183
184         groupedValueList.Add(value);
185       }
186
187       return groupedValues;
188     }
189
190     /// <summary>
191     /// Adds the elements of the specified collection to the specified generic IList.
192     /// </summary>
193     /// <param name="initial">The list to add to.</param>
194     /// <param name="collection">The collection of elements to add.</param>
195     public static void AddRange<T>(this IList<T> initial, IEnumerable<T> collection)
196     {
197       if (initial == null)
198         throw new ArgumentNullException("initial");
199
200       if (collection == null)
201         return;
202
203       foreach (T value in collection)
204       {
205         initial.Add(value);
206       }
207     }
208
209     public static void AddRange(this IList initial, IEnumerable collection)
210     {
211       ValidationUtils.ArgumentNotNull(initial, "initial");
212
213       ListWrapper<object> wrapper = new ListWrapper<object>(initial);
214       wrapper.AddRange(collection.Cast<object>());
215     }
216
217     public static List<T> Distinct<T>(List<T> collection)
218     {
219       List<T> distinctList = new List<T>();
220
221       foreach (T value in collection)
222       {
223         if (!distinctList.Contains(value))
224           distinctList.Add(value);
225       }
226
227       return distinctList;
228     }
229
230     public static List<List<T>> Flatten<T>(params IList<T>[] lists)
231     {
232       List<List<T>> flattened = new List<List<T>>();
233       Dictionary<int, T> currentList = new Dictionary<int, T>();
234
235       Recurse<T>(new List<IList<T>>(lists), 0, currentList, flattened);
236
237       return flattened;
238     }
239
240     private static void Recurse<T>(IList<IList<T>> global, int current, Dictionary<int, T> currentSet, List<List<T>> flattenedResult)
241     {
242       IList<T> currentArray = global[current];
243
244       for (int i = 0; i < currentArray.Count; i++)
245       {
246         currentSet[current] = currentArray[i];
247
248         if (current == global.Count - 1)
249         {
250           List<T> items = new List<T>();
251
252           for (int k = 0; k < currentSet.Count; k++)
253           {
254             items.Add(currentSet[k]);
255           }
256
257           flattenedResult.Add(items);
258         }
259         else
260         {
261           Recurse(global, current + 1, currentSet, flattenedResult);
262         }
263       }
264     }
265
266     public static List<T> CreateList<T>(ICollection collection)
267     {
268       if (collection == null)
269         throw new ArgumentNullException("collection");
270
271       T[] array = new T[collection.Count];
272       collection.CopyTo(array, 0);
273
274       return new List<T>(array);
275     }
276
277     public static bool ListEquals<T>(IList<T> a, IList<T> b)
278     {
279       if (a == null || b == null)
280         return (a == null && b == null);
281
282       if (a.Count != b.Count)
283         return false;
284
285       EqualityComparer<T> comparer = EqualityComparer<T>.Default;
286
287       for (int i = 0; i < a.Count; i++)
288       {
289         if (!comparer.Equals(a[i], b[i]))
290           return false;
291       }
292
293       return true;
294     }
295
296     #region GetSingleItem
297     public static bool TryGetSingleItem<T>(IList<T> list, out T value)
298     {
299       return TryGetSingleItem<T>(list, false, out value);
300     }
301
302     public static bool TryGetSingleItem<T>(IList<T> list, bool returnDefaultIfEmpty, out T value)
303     {
304       return MiscellaneousUtils.TryAction<T>(delegate { return GetSingleItem(list, returnDefaultIfEmpty); }, out value);
305     }
306
307     public static T GetSingleItem<T>(IList<T> list)
308     {
309       return GetSingleItem<T>(list, false);
310     }
311
312     public static T GetSingleItem<T>(IList<T> list, bool returnDefaultIfEmpty)
313     {
314       if (list.Count == 1)
315         return list[0];
316       else if (returnDefaultIfEmpty && list.Count == 0)
317         return default(T);
318       else
319         throw new Exception("Expected single {0} in list but got {1}.".FormatWith(CultureInfo.InvariantCulture, typeof(T), list.Count));
320     }
321     #endregion
322
323     public static IList<T> Minus<T>(IList<T> list, IList<T> minus)
324     {
325       ValidationUtils.ArgumentNotNull(list, "list");
326
327       List<T> result = new List<T>(list.Count);
328       foreach (T t in list)
329       {
330         if (minus == null || !minus.Contains(t))
331           result.Add(t);
332       }
333
334       return result;
335     }
336
337     public static IList CreateGenericList(Type listType)
338     {
339       ValidationUtils.ArgumentNotNull(listType, "listType");
340
341       return (IList)ReflectionUtils.CreateGeneric(typeof(List<>), listType);
342     }
343
344     public static IDictionary CreateGenericDictionary(Type keyType, Type valueType)
345     {
346       ValidationUtils.ArgumentNotNull(keyType, "keyType");
347       ValidationUtils.ArgumentNotNull(valueType, "valueType");
348
349       return (IDictionary)ReflectionUtils.CreateGeneric(typeof(Dictionary<,>), keyType, valueType);
350     }
351
352     public static bool IsListType(Type type)
353     {
354       ValidationUtils.ArgumentNotNull(type, "type");
355
356       if (type.IsArray)
357         return true;
358       if (typeof(IList).IsAssignableFrom(type))
359         return true;
360       if (ReflectionUtils.ImplementsGenericDefinition(type, typeof(IList<>)))
361         return true;
362
363       return false;
364     }
365
366     public static bool IsCollectionType(Type type)
367     {
368       ValidationUtils.ArgumentNotNull(type, "type");
369
370       if (type.IsArray)
371         return true;
372       if (typeof(ICollection).IsAssignableFrom(type))
373         return true;
374       if (ReflectionUtils.ImplementsGenericDefinition(type, typeof(ICollection<>)))
375         return true;
376
377       return false;
378     }
379
380     public static bool IsDictionaryType(Type type)
381     {
382       ValidationUtils.ArgumentNotNull(type, "type");
383
384       if (typeof(IDictionary).IsAssignableFrom(type))
385         return true;
386       if (ReflectionUtils.ImplementsGenericDefinition(type, typeof (IDictionary<,>)))
387         return true;
388
389       return false;
390     }
391
392     public static IWrappedCollection CreateCollectionWrapper(object list)
393     {
394       ValidationUtils.ArgumentNotNull(list, "list");
395
396       Type collectionDefinition;
397       if (ReflectionUtils.ImplementsGenericDefinition(list.GetType(), typeof(ICollection<>), out collectionDefinition))
398       {
399         Type collectionItemType = ReflectionUtils.GetCollectionItemType(collectionDefinition);
400
401         // Activator.CreateInstance throws AmbiguousMatchException. Manually invoke constructor
402         Func<Type, IList<object>, object> instanceCreator = (t, a) =>
403         {
404           ConstructorInfo c = t.GetConstructor(new[] { collectionDefinition });
405           return c.Invoke(new[] { list });
406         };
407
408         return (IWrappedCollection)ReflectionUtils.CreateGeneric(typeof(CollectionWrapper<>), new[] { collectionItemType }, instanceCreator, list);
409       }
410       else if (list is IList)
411       {
412         return new CollectionWrapper<object>((IList)list);
413       }
414       else
415       {
416         throw new Exception("Can not create ListWrapper for type {0}.".FormatWith(CultureInfo.InvariantCulture, list.GetType()));
417       }
418     }
419     public static IWrappedList CreateListWrapper(object list)
420     {
421       ValidationUtils.ArgumentNotNull(list, "list");
422
423       Type listDefinition;
424       if (ReflectionUtils.ImplementsGenericDefinition(list.GetType(), typeof(IList<>), out listDefinition))
425       {
426         Type collectionItemType = ReflectionUtils.GetCollectionItemType(listDefinition);
427
428         // Activator.CreateInstance throws AmbiguousMatchException. Manually invoke constructor
429         Func<Type, IList<object>, object> instanceCreator = (t, a) =>
430         {
431           ConstructorInfo c = t.GetConstructor(new[] {listDefinition});
432           return c.Invoke(new[] { list });
433         };
434
435         return (IWrappedList)ReflectionUtils.CreateGeneric(typeof(ListWrapper<>), new[] { collectionItemType }, instanceCreator, list);
436       }
437       else if (list is IList)
438       {
439         return new ListWrapper<object>((IList)list);
440       }
441       else
442       {
443         throw new Exception("Can not create ListWrapper for type {0}.".FormatWith(CultureInfo.InvariantCulture, list.GetType()));
444       }
445     }
446
447     public static IWrappedDictionary CreateDictionaryWrapper(object dictionary)
448     {
449       ValidationUtils.ArgumentNotNull(dictionary, "dictionary");
450
451       Type dictionaryDefinition;
452       if (ReflectionUtils.ImplementsGenericDefinition(dictionary.GetType(), typeof(IDictionary<,>), out dictionaryDefinition))
453       {
454         Type dictionaryKeyType = ReflectionUtils.GetDictionaryKeyType(dictionaryDefinition);
455         Type dictionaryValueType = ReflectionUtils.GetDictionaryValueType(dictionaryDefinition);
456
457         // Activator.CreateInstance throws AmbiguousMatchException. Manually invoke constructor
458         Func<Type, IList<object>, object> instanceCreator = (t, a) =>
459         {
460           ConstructorInfo c = t.GetConstructor(new[] { dictionaryDefinition });
461           return c.Invoke(new[] { dictionary });
462         };
463
464         return (IWrappedDictionary)ReflectionUtils.CreateGeneric(typeof(DictionaryWrapper<,>), new[] { dictionaryKeyType, dictionaryValueType }, instanceCreator, dictionary);
465       }
466       else if (dictionary is IDictionary)
467       {
468         return new DictionaryWrapper<object, object>((IDictionary)dictionary);
469       }
470       else
471       {
472         throw new Exception("Can not create DictionaryWrapper for type {0}.".FormatWith(CultureInfo.InvariantCulture, dictionary.GetType()));
473       }
474     }
475
476     public static object CreateAndPopulateList(Type listType, Action<IList, bool> populateList)
477     {
478       ValidationUtils.ArgumentNotNull(listType, "listType");
479       ValidationUtils.ArgumentNotNull(populateList, "populateList");
480
481       IList list;
482       Type collectionType;
483       bool isReadOnlyOrFixedSize = false;
484
485       if (listType.IsArray)
486       {
487         // have to use an arraylist when creating array
488         // there is no way to know the size until it is finised
489         list = new List<object>();
490         isReadOnlyOrFixedSize = true;
491       }
492       else if (ReflectionUtils.InheritsGenericDefinition(listType, typeof(ReadOnlyCollection<>), out collectionType))
493       {
494         Type readOnlyCollectionContentsType = collectionType.GetGenericArguments()[0];
495         Type genericEnumerable = ReflectionUtils.MakeGenericType(typeof(IEnumerable<>), readOnlyCollectionContentsType);
496         bool suitableConstructor = false;
497
498         foreach (ConstructorInfo constructor in listType.GetConstructors())
499         {
500           IList<ParameterInfo> parameters = constructor.GetParameters();
501
502           if (parameters.Count == 1)
503           {
504             if (genericEnumerable.IsAssignableFrom(parameters[0].ParameterType))
505             {
506               suitableConstructor = true;
507               break;
508             }
509           }
510         }
511
512         if (!suitableConstructor)
513           throw new Exception("Read-only type {0} does not have a public constructor that takes a type that implements {1}.".FormatWith(CultureInfo.InvariantCulture, listType, genericEnumerable));
514
515         // can't add or modify a readonly list
516         // use List<T> and convert once populated
517         list = CreateGenericList(readOnlyCollectionContentsType);
518         isReadOnlyOrFixedSize = true;
519       }
520       else if (typeof(IList).IsAssignableFrom(listType))
521       {
522         if (ReflectionUtils.IsInstantiatableType(listType))
523           list = (IList)Activator.CreateInstance(listType);
524         else if (listType == typeof(IList))
525           list = new List<object>();
526         else
527           list = null;
528       }
529       else if (ReflectionUtils.ImplementsGenericDefinition(listType, typeof(ICollection<>)))
530       {
531         if (ReflectionUtils.IsInstantiatableType(listType))
532           list = CreateCollectionWrapper(Activator.CreateInstance(listType));
533         else
534           list = null;
535       }
536       else
537       {
538         list = null;
539       }
540
541       if (list == null)
542         throw new Exception("Cannot create and populate list type {0}.".FormatWith(CultureInfo.InvariantCulture, listType));
543
544       populateList(list, isReadOnlyOrFixedSize);
545
546       // create readonly and fixed sized collections using the temporary list
547       if (isReadOnlyOrFixedSize)
548       {
549         if (listType.IsArray)
550           list = ToArray(((List<object>)list).ToArray(), ReflectionUtils.GetCollectionItemType(listType));
551         else if (ReflectionUtils.InheritsGenericDefinition(listType, typeof(ReadOnlyCollection<>)))
552           list = (IList)ReflectionUtils.CreateInstance(listType, list);
553       }
554       else if (list is IWrappedCollection)
555       {
556         return ((IWrappedCollection) list).UnderlyingCollection;
557       }
558
559       return list;
560     }
561
562     public static Array ToArray(Array initial, Type type)
563     {
564       if (type == null)
565         throw new ArgumentNullException("type");
566
567       Array destinationArray = Array.CreateInstance(type, initial.Length);
568       Array.Copy(initial, 0, destinationArray, 0, initial.Length);
569       return destinationArray;
570     }
571
572     public static bool AddDistinct<T>(this IList<T> list, T value)
573     {
574       return list.AddDistinct(value, EqualityComparer<T>.Default);
575     }
576
577     public static bool AddDistinct<T>(this IList<T> list, T value, IEqualityComparer<T> comparer)
578     {
579       if (list.ContainsValue(value, comparer))
580         return false;
581
582       list.Add(value);
583       return true;
584     }
585
586     // this is here because LINQ Bridge doesn't support Contains with IEqualityComparer<T>
587     public static bool ContainsValue<TSource>(this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer)
588     {
589       if (comparer == null)
590         comparer = EqualityComparer<TSource>.Default;
591
592       if (source == null)
593         throw new ArgumentNullException("source");
594
595       foreach (TSource local in source)
596       {
597         if (comparer.Equals(local, value))
598           return true;
599       }
600
601       return false;
602     }
603
604     public static bool AddRangeDistinct<T>(this IList<T> list, IEnumerable<T> values)
605     {
606       return list.AddRangeDistinct(values, EqualityComparer<T>.Default);
607     }
608
609     public static bool AddRangeDistinct<T>(this IList<T> list, IEnumerable<T> values, IEqualityComparer<T> comparer)
610     {
611       bool allAdded = true;
612       foreach (T value in values)
613       {
614         if (!list.AddDistinct(value, comparer))
615           allAdded = false;
616       }
617
618       return allAdded;
619     }
620
621     public static int IndexOf<T>(this IEnumerable<T> collection, Func<T, bool> predicate)
622     {
623       int index = 0;
624       foreach (T value in collection)
625       {
626         if (predicate(value))
627           return index;
628
629         index++;
630       }
631
632       return -1;
633     }
634   }
635 }