PageRenderTime 56ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/Net.SuddenElfilio.RilSharp/JSON/Utilities/CollectionUtils.cs

https://bitbucket.org/suddenelfilio/rilsharp
C# | 635 lines | 441 code | 107 blank | 87 comment | 99 complexity | bfd3dab82332af62037f02e45e948329 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. using System.Linq;
  32. using System.Globalization;
  33. namespace Newtonsoft.Json.Utilities
  34. {
  35. internal static class CollectionUtils
  36. {
  37. public static IEnumerable<T> CastValid<T>(this IEnumerable enumerable)
  38. {
  39. ValidationUtils.ArgumentNotNull(enumerable, "enumerable");
  40. return enumerable.Cast<object>().Where(o => o is T).Cast<T>();
  41. }
  42. public static List<T> CreateList<T>(params T[] values)
  43. {
  44. return new List<T>(values);
  45. }
  46. /// <summary>
  47. /// Determines whether the collection is null or empty.
  48. /// </summary>
  49. /// <param name="collection">The collection.</param>
  50. /// <returns>
  51. /// <c>true</c> if the collection is null or empty; otherwise, <c>false</c>.
  52. /// </returns>
  53. public static bool IsNullOrEmpty(ICollection collection)
  54. {
  55. if (collection != null)
  56. {
  57. return (collection.Count == 0);
  58. }
  59. return true;
  60. }
  61. /// <summary>
  62. /// Determines whether the collection is null or empty.
  63. /// </summary>
  64. /// <param name="collection">The collection.</param>
  65. /// <returns>
  66. /// <c>true</c> if the collection is null or empty; otherwise, <c>false</c>.
  67. /// </returns>
  68. public static bool IsNullOrEmpty<T>(ICollection<T> collection)
  69. {
  70. if (collection != null)
  71. {
  72. return (collection.Count == 0);
  73. }
  74. return true;
  75. }
  76. /// <summary>
  77. /// Determines whether the collection is null, empty or its contents are uninitialized values.
  78. /// </summary>
  79. /// <param name="list">The list.</param>
  80. /// <returns>
  81. /// <c>true</c> if the collection is null or empty or its contents are uninitialized values; otherwise, <c>false</c>.
  82. /// </returns>
  83. public static bool IsNullOrEmptyOrDefault<T>(IList<T> list)
  84. {
  85. if (IsNullOrEmpty<T>(list))
  86. return true;
  87. return ReflectionUtils.ItemsUnitializedValue<T>(list);
  88. }
  89. /// <summary>
  90. /// Makes a slice of the specified list in between the start and end indexes.
  91. /// </summary>
  92. /// <param name="list">The list.</param>
  93. /// <param name="start">The start index.</param>
  94. /// <param name="end">The end index.</param>
  95. /// <returns>A slice of the list.</returns>
  96. public static IList<T> Slice<T>(IList<T> list, int? start, int? end)
  97. {
  98. return Slice<T>(list, start, end, null);
  99. }
  100. /// <summary>
  101. /// Makes a slice of the specified list in between the start and end indexes,
  102. /// getting every so many items based upon the step.
  103. /// </summary>
  104. /// <param name="list">The list.</param>
  105. /// <param name="start">The start index.</param>
  106. /// <param name="end">The end index.</param>
  107. /// <param name="step">The step.</param>
  108. /// <returns>A slice of the list.</returns>
  109. public static IList<T> Slice<T>(IList<T> list, int? start, int? end, int? step)
  110. {
  111. if (list == null)
  112. throw new ArgumentNullException("list");
  113. if (step == 0)
  114. throw new ArgumentException("Step cannot be zero.", "step");
  115. List<T> slicedList = new List<T>();
  116. // nothing to slice
  117. if (list.Count == 0)
  118. return slicedList;
  119. // set defaults for null arguments
  120. int s = step ?? 1;
  121. int startIndex = start ?? 0;
  122. int endIndex = end ?? list.Count;
  123. // start from the end of the list if start is negitive
  124. startIndex = (startIndex < 0) ? list.Count + startIndex : startIndex;
  125. // end from the start of the list if end is negitive
  126. endIndex = (endIndex < 0) ? list.Count + endIndex : endIndex;
  127. // ensure indexes keep within collection bounds
  128. startIndex = Math.Max(startIndex, 0);
  129. endIndex = Math.Min(endIndex, list.Count - 1);
  130. // loop between start and end indexes, incrementing by the step
  131. for (int i = startIndex; i < endIndex; i += s)
  132. {
  133. slicedList.Add(list[i]);
  134. }
  135. return slicedList;
  136. }
  137. /// <summary>
  138. /// Group the collection using a function which returns the key.
  139. /// </summary>
  140. /// <param name="source">The source collection to group.</param>
  141. /// <param name="keySelector">The key selector.</param>
  142. /// <returns>A Dictionary with each key relating to a list of objects in a list grouped under it.</returns>
  143. public static Dictionary<K, List<V>> GroupBy<K, V>(ICollection<V> source, Func<V, K> keySelector)
  144. {
  145. if (keySelector == null)
  146. throw new ArgumentNullException("keySelector");
  147. Dictionary<K, List<V>> groupedValues = new Dictionary<K, List<V>>();
  148. foreach (V value in source)
  149. {
  150. // using delegate to get the value's key
  151. K key = keySelector(value);
  152. List<V> groupedValueList;
  153. // add a list for grouped values if the key is not already in Dictionary
  154. if (!groupedValues.TryGetValue(key, out groupedValueList))
  155. {
  156. groupedValueList = new List<V>();
  157. groupedValues.Add(key, groupedValueList);
  158. }
  159. groupedValueList.Add(value);
  160. }
  161. return groupedValues;
  162. }
  163. /// <summary>
  164. /// Adds the elements of the specified collection to the specified generic IList.
  165. /// </summary>
  166. /// <param name="initial">The list to add to.</param>
  167. /// <param name="collection">The collection of elements to add.</param>
  168. public static void AddRange<T>(this IList<T> initial, IEnumerable<T> collection)
  169. {
  170. if (initial == null)
  171. throw new ArgumentNullException("initial");
  172. if (collection == null)
  173. return;
  174. foreach (T value in collection)
  175. {
  176. initial.Add(value);
  177. }
  178. }
  179. public static void AddRange(this IList initial, IEnumerable collection)
  180. {
  181. ValidationUtils.ArgumentNotNull(initial, "initial");
  182. ListWrapper<object> wrapper = new ListWrapper<object>(initial);
  183. wrapper.AddRange(collection.Cast<object>());
  184. }
  185. public static List<T> Distinct<T>(List<T> collection)
  186. {
  187. List<T> distinctList = new List<T>();
  188. foreach (T value in collection)
  189. {
  190. if (!distinctList.Contains(value))
  191. distinctList.Add(value);
  192. }
  193. return distinctList;
  194. }
  195. public static List<List<T>> Flatten<T>(params IList<T>[] lists)
  196. {
  197. List<List<T>> flattened = new List<List<T>>();
  198. Dictionary<int, T> currentList = new Dictionary<int, T>();
  199. Recurse<T>(new List<IList<T>>(lists), 0, currentList, flattened);
  200. return flattened;
  201. }
  202. private static void Recurse<T>(IList<IList<T>> global, int current, Dictionary<int, T> currentSet, List<List<T>> flattenedResult)
  203. {
  204. IList<T> currentArray = global[current];
  205. for (int i = 0; i < currentArray.Count; i++)
  206. {
  207. currentSet[current] = currentArray[i];
  208. if (current == global.Count - 1)
  209. {
  210. List<T> items = new List<T>();
  211. for (int k = 0; k < currentSet.Count; k++)
  212. {
  213. items.Add(currentSet[k]);
  214. }
  215. flattenedResult.Add(items);
  216. }
  217. else
  218. {
  219. Recurse(global, current + 1, currentSet, flattenedResult);
  220. }
  221. }
  222. }
  223. public static List<T> CreateList<T>(ICollection collection)
  224. {
  225. if (collection == null)
  226. throw new ArgumentNullException("collection");
  227. T[] array = new T[collection.Count];
  228. collection.CopyTo(array, 0);
  229. return new List<T>(array);
  230. }
  231. public static bool ListEquals<T>(IList<T> a, IList<T> b)
  232. {
  233. if (a == null || b == null)
  234. return (a == null && b == null);
  235. if (a.Count != b.Count)
  236. return false;
  237. EqualityComparer<T> comparer = EqualityComparer<T>.Default;
  238. for (int i = 0; i < a.Count; i++)
  239. {
  240. if (!comparer.Equals(a[i], b[i]))
  241. return false;
  242. }
  243. return true;
  244. }
  245. #region GetSingleItem
  246. public static bool TryGetSingleItem<T>(IList<T> list, out T value)
  247. {
  248. return TryGetSingleItem<T>(list, false, out value);
  249. }
  250. public static bool TryGetSingleItem<T>(IList<T> list, bool returnDefaultIfEmpty, out T value)
  251. {
  252. return MiscellaneousUtils.TryAction<T>(delegate { return GetSingleItem(list, returnDefaultIfEmpty); }, out value);
  253. }
  254. public static T GetSingleItem<T>(IList<T> list)
  255. {
  256. return GetSingleItem<T>(list, false);
  257. }
  258. public static T GetSingleItem<T>(IList<T> list, bool returnDefaultIfEmpty)
  259. {
  260. if (list.Count == 1)
  261. return list[0];
  262. else if (returnDefaultIfEmpty && list.Count == 0)
  263. return default(T);
  264. else
  265. throw new Exception("Expected single {0} in list but got {1}.".FormatWith(CultureInfo.InvariantCulture, typeof(T), list.Count));
  266. }
  267. #endregion
  268. public static IList<T> Minus<T>(IList<T> list, IList<T> minus)
  269. {
  270. ValidationUtils.ArgumentNotNull(list, "list");
  271. List<T> result = new List<T>(list.Count);
  272. foreach (T t in list)
  273. {
  274. if (minus == null || !minus.Contains(t))
  275. result.Add(t);
  276. }
  277. return result;
  278. }
  279. public static IList CreateGenericList(Type listType)
  280. {
  281. ValidationUtils.ArgumentNotNull(listType, "listType");
  282. return (IList)ReflectionUtils.CreateGeneric(typeof(List<>), listType);
  283. }
  284. public static IDictionary CreateGenericDictionary(Type keyType, Type valueType)
  285. {
  286. ValidationUtils.ArgumentNotNull(keyType, "keyType");
  287. ValidationUtils.ArgumentNotNull(valueType, "valueType");
  288. return (IDictionary)ReflectionUtils.CreateGeneric(typeof(Dictionary<,>), keyType, valueType);
  289. }
  290. public static bool IsListType(Type type)
  291. {
  292. ValidationUtils.ArgumentNotNull(type, "type");
  293. if (type.IsArray)
  294. return true;
  295. if (typeof(IList).IsAssignableFrom(type))
  296. return true;
  297. if (ReflectionUtils.ImplementsGenericDefinition(type, typeof(IList<>)))
  298. return true;
  299. return false;
  300. }
  301. public static bool IsCollectionType(Type type)
  302. {
  303. ValidationUtils.ArgumentNotNull(type, "type");
  304. if (type.IsArray)
  305. return true;
  306. if (typeof(ICollection).IsAssignableFrom(type))
  307. return true;
  308. if (ReflectionUtils.ImplementsGenericDefinition(type, typeof(ICollection<>)))
  309. return true;
  310. return false;
  311. }
  312. public static bool IsDictionaryType(Type type)
  313. {
  314. ValidationUtils.ArgumentNotNull(type, "type");
  315. if (typeof(IDictionary).IsAssignableFrom(type))
  316. return true;
  317. if (ReflectionUtils.ImplementsGenericDefinition(type, typeof (IDictionary<,>)))
  318. return true;
  319. return false;
  320. }
  321. public static IWrappedCollection CreateCollectionWrapper(object list)
  322. {
  323. ValidationUtils.ArgumentNotNull(list, "list");
  324. Type collectionDefinition;
  325. if (ReflectionUtils.ImplementsGenericDefinition(list.GetType(), typeof(ICollection<>), out collectionDefinition))
  326. {
  327. Type collectionItemType = ReflectionUtils.GetCollectionItemType(collectionDefinition);
  328. // Activator.CreateInstance throws AmbiguousMatchException. Manually invoke constructor
  329. Func<Type, IList<object>, object> instanceCreator = (t, a) =>
  330. {
  331. ConstructorInfo c = t.GetConstructor(new[] { collectionDefinition });
  332. return c.Invoke(new[] { list });
  333. };
  334. return (IWrappedCollection)ReflectionUtils.CreateGeneric(typeof(CollectionWrapper<>), new[] { collectionItemType }, instanceCreator, list);
  335. }
  336. else if (list is IList)
  337. {
  338. return new CollectionWrapper<object>((IList)list);
  339. }
  340. else
  341. {
  342. throw new Exception("Can not create ListWrapper for type {0}.".FormatWith(CultureInfo.InvariantCulture, list.GetType()));
  343. }
  344. }
  345. public static IWrappedList CreateListWrapper(object list)
  346. {
  347. ValidationUtils.ArgumentNotNull(list, "list");
  348. Type listDefinition;
  349. if (ReflectionUtils.ImplementsGenericDefinition(list.GetType(), typeof(IList<>), out listDefinition))
  350. {
  351. Type collectionItemType = ReflectionUtils.GetCollectionItemType(listDefinition);
  352. // Activator.CreateInstance throws AmbiguousMatchException. Manually invoke constructor
  353. Func<Type, IList<object>, object> instanceCreator = (t, a) =>
  354. {
  355. ConstructorInfo c = t.GetConstructor(new[] {listDefinition});
  356. return c.Invoke(new[] { list });
  357. };
  358. return (IWrappedList)ReflectionUtils.CreateGeneric(typeof(ListWrapper<>), new[] { collectionItemType }, instanceCreator, list);
  359. }
  360. else if (list is IList)
  361. {
  362. return new ListWrapper<object>((IList)list);
  363. }
  364. else
  365. {
  366. throw new Exception("Can not create ListWrapper for type {0}.".FormatWith(CultureInfo.InvariantCulture, list.GetType()));
  367. }
  368. }
  369. public static IWrappedDictionary CreateDictionaryWrapper(object dictionary)
  370. {
  371. ValidationUtils.ArgumentNotNull(dictionary, "dictionary");
  372. Type dictionaryDefinition;
  373. if (ReflectionUtils.ImplementsGenericDefinition(dictionary.GetType(), typeof(IDictionary<,>), out dictionaryDefinition))
  374. {
  375. Type dictionaryKeyType = ReflectionUtils.GetDictionaryKeyType(dictionaryDefinition);
  376. Type dictionaryValueType = ReflectionUtils.GetDictionaryValueType(dictionaryDefinition);
  377. // Activator.CreateInstance throws AmbiguousMatchException. Manually invoke constructor
  378. Func<Type, IList<object>, object> instanceCreator = (t, a) =>
  379. {
  380. ConstructorInfo c = t.GetConstructor(new[] { dictionaryDefinition });
  381. return c.Invoke(new[] { dictionary });
  382. };
  383. return (IWrappedDictionary)ReflectionUtils.CreateGeneric(typeof(DictionaryWrapper<,>), new[] { dictionaryKeyType, dictionaryValueType }, instanceCreator, dictionary);
  384. }
  385. else if (dictionary is IDictionary)
  386. {
  387. return new DictionaryWrapper<object, object>((IDictionary)dictionary);
  388. }
  389. else
  390. {
  391. throw new Exception("Can not create DictionaryWrapper for type {0}.".FormatWith(CultureInfo.InvariantCulture, dictionary.GetType()));
  392. }
  393. }
  394. public static object CreateAndPopulateList(Type listType, Action<IList, bool> populateList)
  395. {
  396. ValidationUtils.ArgumentNotNull(listType, "listType");
  397. ValidationUtils.ArgumentNotNull(populateList, "populateList");
  398. IList list;
  399. Type collectionType;
  400. bool isReadOnlyOrFixedSize = false;
  401. if (listType.IsArray)
  402. {
  403. // have to use an arraylist when creating array
  404. // there is no way to know the size until it is finised
  405. list = new List<object>();
  406. isReadOnlyOrFixedSize = true;
  407. }
  408. else if (ReflectionUtils.InheritsGenericDefinition(listType, typeof(ReadOnlyCollection<>), out collectionType))
  409. {
  410. Type readOnlyCollectionContentsType = collectionType.GetGenericArguments()[0];
  411. Type genericEnumerable = ReflectionUtils.MakeGenericType(typeof(IEnumerable<>), readOnlyCollectionContentsType);
  412. bool suitableConstructor = false;
  413. foreach (ConstructorInfo constructor in listType.GetConstructors())
  414. {
  415. IList<ParameterInfo> parameters = constructor.GetParameters();
  416. if (parameters.Count == 1)
  417. {
  418. if (genericEnumerable.IsAssignableFrom(parameters[0].ParameterType))
  419. {
  420. suitableConstructor = true;
  421. break;
  422. }
  423. }
  424. }
  425. if (!suitableConstructor)
  426. 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));
  427. // can't add or modify a readonly list
  428. // use List<T> and convert once populated
  429. list = CreateGenericList(readOnlyCollectionContentsType);
  430. isReadOnlyOrFixedSize = true;
  431. }
  432. else if (typeof(IList).IsAssignableFrom(listType))
  433. {
  434. if (ReflectionUtils.IsInstantiatableType(listType))
  435. list = (IList)Activator.CreateInstance(listType);
  436. else if (listType == typeof(IList))
  437. list = new List<object>();
  438. else
  439. list = null;
  440. }
  441. else if (ReflectionUtils.ImplementsGenericDefinition(listType, typeof(ICollection<>)))
  442. {
  443. if (ReflectionUtils.IsInstantiatableType(listType))
  444. list = CreateCollectionWrapper(Activator.CreateInstance(listType));
  445. else
  446. list = null;
  447. }
  448. else
  449. {
  450. list = null;
  451. }
  452. if (list == null)
  453. throw new Exception("Cannot create and populate list type {0}.".FormatWith(CultureInfo.InvariantCulture, listType));
  454. populateList(list, isReadOnlyOrFixedSize);
  455. // create readonly and fixed sized collections using the temporary list
  456. if (isReadOnlyOrFixedSize)
  457. {
  458. if (listType.IsArray)
  459. list = ToArray(((List<object>)list).ToArray(), ReflectionUtils.GetCollectionItemType(listType));
  460. else if (ReflectionUtils.InheritsGenericDefinition(listType, typeof(ReadOnlyCollection<>)))
  461. list = (IList)ReflectionUtils.CreateInstance(listType, list);
  462. }
  463. else if (list is IWrappedCollection)
  464. {
  465. return ((IWrappedCollection) list).UnderlyingCollection;
  466. }
  467. return list;
  468. }
  469. public static Array ToArray(Array initial, Type type)
  470. {
  471. if (type == null)
  472. throw new ArgumentNullException("type");
  473. Array destinationArray = Array.CreateInstance(type, initial.Length);
  474. Array.Copy(initial, 0, destinationArray, 0, initial.Length);
  475. return destinationArray;
  476. }
  477. public static bool AddDistinct<T>(this IList<T> list, T value)
  478. {
  479. return list.AddDistinct(value, EqualityComparer<T>.Default);
  480. }
  481. public static bool AddDistinct<T>(this IList<T> list, T value, IEqualityComparer<T> comparer)
  482. {
  483. if (list.ContainsValue(value, comparer))
  484. return false;
  485. list.Add(value);
  486. return true;
  487. }
  488. // this is here because LINQ Bridge doesn't support Contains with IEqualityComparer<T>
  489. public static bool ContainsValue<TSource>(this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer)
  490. {
  491. if (comparer == null)
  492. comparer = EqualityComparer<TSource>.Default;
  493. if (source == null)
  494. throw new ArgumentNullException("source");
  495. foreach (TSource local in source)
  496. {
  497. if (comparer.Equals(local, value))
  498. return true;
  499. }
  500. return false;
  501. }
  502. public static bool AddRangeDistinct<T>(this IList<T> list, IEnumerable<T> values)
  503. {
  504. return list.AddRangeDistinct(values, EqualityComparer<T>.Default);
  505. }
  506. public static bool AddRangeDistinct<T>(this IList<T> list, IEnumerable<T> values, IEqualityComparer<T> comparer)
  507. {
  508. bool allAdded = true;
  509. foreach (T value in values)
  510. {
  511. if (!list.AddDistinct(value, comparer))
  512. allAdded = false;
  513. }
  514. return allAdded;
  515. }
  516. public static int IndexOf<T>(this IEnumerable<T> collection, Func<T, bool> predicate)
  517. {
  518. int index = 0;
  519. foreach (T value in collection)
  520. {
  521. if (predicate(value))
  522. return index;
  523. index++;
  524. }
  525. return -1;
  526. }
  527. }
  528. }