PageRenderTime 53ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/Newtonsoft.Json/Modules/Utilities/CollectionUtils.cs

https://bitbucket.org/VirtualReality/3rdparty-addon-modules
C# | 330 lines | 235 code | 46 blank | 49 comment | 44 complexity | 0e7c52f09bf0f7c739be85546a4e0b6d MD5 | raw file
  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. using System;
  26. using System.Collections.Generic;
  27. using System.Collections.ObjectModel;
  28. using System.Reflection;
  29. using System.Text;
  30. using System.Collections;
  31. #if NET20
  32. using Newtonsoft.Json.Utilities.LinqBridge;
  33. #else
  34. using System.Linq;
  35. #endif
  36. using System.Globalization;
  37. using Newtonsoft.Json.Serialization;
  38. namespace Newtonsoft.Json.Utilities
  39. {
  40. internal static class CollectionUtils
  41. {
  42. public static IEnumerable<T> CastValid<T>(this IEnumerable enumerable)
  43. {
  44. ValidationUtils.ArgumentNotNull(enumerable, "enumerable");
  45. return enumerable.Cast<object>().Where(o => o is T).Cast<T>();
  46. }
  47. /// <summary>
  48. /// Determines whether the collection is null or empty.
  49. /// </summary>
  50. /// <param name="collection">The collection.</param>
  51. /// <returns>
  52. /// <c>true</c> if the collection is null or empty; otherwise, <c>false</c>.
  53. /// </returns>
  54. public static bool IsNullOrEmpty<T>(ICollection<T> collection)
  55. {
  56. if (collection != null)
  57. {
  58. return (collection.Count == 0);
  59. }
  60. return true;
  61. }
  62. /// <summary>
  63. /// Adds the elements of the specified collection to the specified generic IList.
  64. /// </summary>
  65. /// <param name="initial">The list to add to.</param>
  66. /// <param name="collection">The collection of elements to add.</param>
  67. public static void AddRange<T>(this IList<T> initial, IEnumerable<T> collection)
  68. {
  69. if (initial == null)
  70. throw new ArgumentNullException("initial");
  71. if (collection == null)
  72. return;
  73. foreach (T value in collection)
  74. {
  75. initial.Add(value);
  76. }
  77. }
  78. public static void AddRange(this IList initial, IEnumerable collection)
  79. {
  80. ValidationUtils.ArgumentNotNull(initial, "initial");
  81. ListWrapper<object> wrapper = new ListWrapper<object>(initial);
  82. wrapper.AddRange(collection.Cast<object>());
  83. }
  84. public static IList CreateGenericList(Type listType)
  85. {
  86. ValidationUtils.ArgumentNotNull(listType, "listType");
  87. return (IList)ReflectionUtils.CreateGeneric(typeof(List<>), listType);
  88. }
  89. public static bool IsDictionaryType(Type type)
  90. {
  91. ValidationUtils.ArgumentNotNull(type, "type");
  92. if (typeof(IDictionary).IsAssignableFrom(type))
  93. return true;
  94. if (ReflectionUtils.ImplementsGenericDefinition(type, typeof (IDictionary<,>)))
  95. return true;
  96. return false;
  97. }
  98. public static IWrappedCollection CreateCollectionWrapper(object list)
  99. {
  100. ValidationUtils.ArgumentNotNull(list, "list");
  101. Type collectionDefinition;
  102. if (ReflectionUtils.ImplementsGenericDefinition(list.GetType(), typeof(ICollection<>), out collectionDefinition))
  103. {
  104. Type collectionItemType = ReflectionUtils.GetCollectionItemType(collectionDefinition);
  105. // Activator.CreateInstance throws AmbiguousMatchException. Manually invoke constructor
  106. Func<Type, IList<object>, object> instanceCreator = (t, a) =>
  107. {
  108. ConstructorInfo c = t.GetConstructor(new[] { collectionDefinition });
  109. return c.Invoke(new[] { list });
  110. };
  111. return (IWrappedCollection)ReflectionUtils.CreateGeneric(typeof(CollectionWrapper<>), new[] { collectionItemType }, instanceCreator, list);
  112. }
  113. else if (list is IList)
  114. {
  115. return new CollectionWrapper<object>((IList)list);
  116. }
  117. else
  118. {
  119. throw new ArgumentException("Can not create ListWrapper for type {0}.".FormatWith(CultureInfo.InvariantCulture, list.GetType()), "list");
  120. }
  121. }
  122. public static IWrappedDictionary CreateDictionaryWrapper(object dictionary)
  123. {
  124. ValidationUtils.ArgumentNotNull(dictionary, "dictionary");
  125. Type dictionaryDefinition;
  126. if (ReflectionUtils.ImplementsGenericDefinition(dictionary.GetType(), typeof(IDictionary<,>), out dictionaryDefinition))
  127. {
  128. Type dictionaryKeyType = ReflectionUtils.GetDictionaryKeyType(dictionaryDefinition);
  129. Type dictionaryValueType = ReflectionUtils.GetDictionaryValueType(dictionaryDefinition);
  130. // Activator.CreateInstance throws AmbiguousMatchException. Manually invoke constructor
  131. Func<Type, IList<object>, object> instanceCreator = (t, a) =>
  132. {
  133. ConstructorInfo c = t.GetConstructor(new[] { dictionaryDefinition });
  134. return c.Invoke(new[] { dictionary });
  135. };
  136. return (IWrappedDictionary)ReflectionUtils.CreateGeneric(typeof(DictionaryWrapper<,>), new[] { dictionaryKeyType, dictionaryValueType }, instanceCreator, dictionary);
  137. }
  138. else if (dictionary is IDictionary)
  139. {
  140. return new DictionaryWrapper<object, object>((IDictionary)dictionary);
  141. }
  142. else
  143. {
  144. throw new ArgumentException("Can not create DictionaryWrapper for type {0}.".FormatWith(CultureInfo.InvariantCulture, dictionary.GetType()), "dictionary");
  145. }
  146. }
  147. public static IList CreateList(Type listType, out bool isReadOnlyOrFixedSize)
  148. {
  149. ValidationUtils.ArgumentNotNull(listType, "listType");
  150. IList list;
  151. Type collectionType;
  152. isReadOnlyOrFixedSize = false;
  153. if (listType.IsArray)
  154. {
  155. // have to use an arraylist when creating array
  156. // there is no way to know the size until it is finised
  157. list = new List<object>();
  158. isReadOnlyOrFixedSize = true;
  159. }
  160. else if (ReflectionUtils.InheritsGenericDefinition(listType, typeof(ReadOnlyCollection<>), out collectionType))
  161. {
  162. Type readOnlyCollectionContentsType = collectionType.GetGenericArguments()[0];
  163. Type genericEnumerable = ReflectionUtils.MakeGenericType(typeof(IEnumerable<>), readOnlyCollectionContentsType);
  164. bool suitableConstructor = false;
  165. foreach (ConstructorInfo constructor in listType.GetConstructors())
  166. {
  167. IList<ParameterInfo> parameters = constructor.GetParameters();
  168. if (parameters.Count == 1)
  169. {
  170. if (genericEnumerable.IsAssignableFrom(parameters[0].ParameterType))
  171. {
  172. suitableConstructor = true;
  173. break;
  174. }
  175. }
  176. }
  177. if (!suitableConstructor)
  178. 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));
  179. // can't add or modify a readonly list
  180. // use List<T> and convert once populated
  181. list = CreateGenericList(readOnlyCollectionContentsType);
  182. isReadOnlyOrFixedSize = true;
  183. }
  184. else if (typeof(IList).IsAssignableFrom(listType))
  185. {
  186. if (ReflectionUtils.IsInstantiatableType(listType))
  187. list = (IList)Activator.CreateInstance(listType);
  188. else if (listType == typeof(IList))
  189. list = new List<object>();
  190. else
  191. list = null;
  192. }
  193. else if (ReflectionUtils.ImplementsGenericDefinition(listType, typeof(ICollection<>)))
  194. {
  195. if (ReflectionUtils.IsInstantiatableType(listType))
  196. list = CreateCollectionWrapper(Activator.CreateInstance(listType));
  197. else
  198. list = null;
  199. }
  200. else
  201. {
  202. list = null;
  203. }
  204. if (list == null)
  205. throw new InvalidOperationException("Cannot create and populate list type {0}.".FormatWith(CultureInfo.InvariantCulture, listType));
  206. return list;
  207. }
  208. public static Array ToArray(Array initial, Type type)
  209. {
  210. if (type == null)
  211. throw new ArgumentNullException("type");
  212. Array destinationArray = Array.CreateInstance(type, initial.Length);
  213. Array.Copy(initial, 0, destinationArray, 0, initial.Length);
  214. return destinationArray;
  215. }
  216. public static bool AddDistinct<T>(this IList<T> list, T value)
  217. {
  218. return list.AddDistinct(value, EqualityComparer<T>.Default);
  219. }
  220. public static bool AddDistinct<T>(this IList<T> list, T value, IEqualityComparer<T> comparer)
  221. {
  222. if (list.ContainsValue(value, comparer))
  223. return false;
  224. list.Add(value);
  225. return true;
  226. }
  227. // this is here because LINQ Bridge doesn't support Contains with IEqualityComparer<T>
  228. public static bool ContainsValue<TSource>(this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer)
  229. {
  230. if (comparer == null)
  231. comparer = EqualityComparer<TSource>.Default;
  232. if (source == null)
  233. throw new ArgumentNullException("source");
  234. foreach (TSource local in source)
  235. {
  236. if (comparer.Equals(local, value))
  237. return true;
  238. }
  239. return false;
  240. }
  241. public static bool AddRangeDistinct<T>(this IList<T> list, IEnumerable<T> values, IEqualityComparer<T> comparer)
  242. {
  243. bool allAdded = true;
  244. foreach (T value in values)
  245. {
  246. if (!list.AddDistinct(value, comparer))
  247. allAdded = false;
  248. }
  249. return allAdded;
  250. }
  251. public static int IndexOf<T>(this IEnumerable<T> collection, Func<T, bool> predicate)
  252. {
  253. int index = 0;
  254. foreach (T value in collection)
  255. {
  256. if (predicate(value))
  257. return index;
  258. index++;
  259. }
  260. return -1;
  261. }
  262. /// <summary>
  263. /// Returns the index of the first occurrence in a sequence by using a specified IEqualityComparer.
  264. /// </summary>
  265. /// <typeparam name="TSource">The type of the elements of source.</typeparam>
  266. /// <param name="list">A sequence in which to locate a value.</param>
  267. /// <param name="value">The object to locate in the sequence</param>
  268. /// <param name="comparer">An equality comparer to compare values.</param>
  269. /// <returns>The zero-based index of the first occurrence of value within the entire sequence, if found; otherwise, –1.</returns>
  270. public static int IndexOf<TSource>(this IEnumerable<TSource> list, TSource value, IEqualityComparer<TSource> comparer)
  271. {
  272. int index = 0;
  273. foreach (TSource item in list)
  274. {
  275. if (comparer.Equals(item, value))
  276. {
  277. return index;
  278. }
  279. index++;
  280. }
  281. return -1;
  282. }
  283. }
  284. }