PageRenderTime 64ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/DICK.B1/IronPython/Runtime/Set.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 1332 lines | 991 code | 276 blank | 65 comment | 139 complexity | dc544e0cf105d02d3cc402fbd156083b MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Diagnostics;
  19. using System.Runtime.CompilerServices;
  20. using System.Text;
  21. using Microsoft.Scripting;
  22. using Microsoft.Scripting.Runtime;
  23. using Microsoft.Scripting.Utils;
  24. using IronPython.Runtime.Operations;
  25. using IronPython.Runtime.Types;
  26. namespace IronPython.Runtime {
  27. /// <summary>
  28. /// Common interface shared by both Set and FrozenSet
  29. /// </summary>
  30. public interface ISet : IEnumerable, IEnumerable<object>, ICollection, IStructuralEquatable, ICodeFormattable
  31. #if CLR2
  32. , IValueEquality
  33. #endif
  34. {
  35. int __len__();
  36. bool __contains__(object value);
  37. PythonTuple __reduce__();
  38. // private methods used for operations between set types.
  39. void PrivAdd(object adding);
  40. void PrivRemove(object removing);
  41. void SetData(IEnumerable set);
  42. #region NonOperator Operations
  43. bool isdisjoint(object s);
  44. bool issubset(object set);
  45. bool issuperset(object set);
  46. ISet union();
  47. ISet union(object s);
  48. ISet union([NotNull] params object[] ss);
  49. ISet intersection();
  50. ISet intersection(object s);
  51. ISet intersection([NotNull] params object[] ss);
  52. ISet difference();
  53. ISet difference(object s);
  54. ISet difference([NotNull] params object[] ss);
  55. ISet symmetric_difference(object s);
  56. #endregion
  57. }
  58. /// <summary>
  59. /// Contains common set functionality between set and frozenSet
  60. /// </summary>
  61. static class SetHelpers {
  62. public static string SetToString(CodeContext/*!*/ context, object set, CommonDictionaryStorage items) {
  63. string setTypeStr;
  64. Type setType = set.GetType();
  65. if (setType == typeof(SetCollection)) {
  66. setTypeStr = "set";
  67. } else if (setType == typeof(FrozenSetCollection)) {
  68. setTypeStr = "frozenset";
  69. } else {
  70. setTypeStr = PythonTypeOps.GetName(set);
  71. }
  72. StringBuilder sb = new StringBuilder();
  73. sb.Append(setTypeStr);
  74. sb.Append("([");
  75. string comma = "";
  76. foreach (object o in items.GetKeys()) {
  77. sb.Append(comma);
  78. sb.Append(PythonOps.Repr(context, o));
  79. comma = ", ";
  80. }
  81. sb.Append("])");
  82. return sb.ToString();
  83. }
  84. /// <summary>
  85. /// Creates a set that can be hashable. If the set is currently a FrozenSet the
  86. /// set is returned. If the set is a normal Set then a FrozenSet is returned
  87. /// with its contents.
  88. /// </summary>
  89. /// <param name="o"></param>
  90. /// <returns></returns>
  91. public static object GetHashableSetIfSet(object o) {
  92. SetCollection asSet = o as SetCollection;
  93. if (asSet != null) {
  94. if (asSet.GetType() != typeof(SetCollection)) {
  95. // subclass of set, need to check if it is hashable
  96. if (IsHashable(asSet)) {
  97. return o;
  98. }
  99. }
  100. return FrozenSetCollection.Make(((IEnumerable)asSet).GetEnumerator());
  101. }
  102. return o;
  103. }
  104. private static bool IsHashable(SetCollection asSet) {
  105. PythonTypeSlot pts;
  106. PythonType pt = DynamicHelpers.GetPythonType(asSet);
  107. object slotValue;
  108. return pt.TryResolveSlot(DefaultContext.Default, "__hash__", out pts) &&
  109. pts.TryGetValue(DefaultContext.Default, asSet, pt, out slotValue) && slotValue != null;
  110. }
  111. public static ISet MakeSet(object setObj) {
  112. Type t = setObj.GetType();
  113. if (t == typeof(SetCollection)) {
  114. return new SetCollection();
  115. } else if (t == typeof(FrozenSetCollection)) {
  116. return new FrozenSetCollection();
  117. } else {
  118. // subclass
  119. PythonType dt = DynamicHelpers.GetPythonType(setObj);
  120. ISet set = PythonCalls.Call(dt) as ISet;
  121. Debug.Assert(set != null);
  122. return set;
  123. }
  124. }
  125. public static ISet MakeSet(object setObj, ISet set) {
  126. Type t = setObj.GetType();
  127. if (t == typeof(SetCollection)) {
  128. return new SetCollection(set);
  129. } else if (t == typeof(FrozenSetCollection)) {
  130. return new FrozenSetCollection(set);
  131. } else {
  132. // subclass
  133. PythonType dt = DynamicHelpers.GetPythonType(setObj);
  134. ISet res = PythonCalls.Call(dt) as ISet;
  135. Debug.Assert(res != null);
  136. res.SetData(set);
  137. return res;
  138. }
  139. }
  140. public static ISet Intersection(ISet x, object y) {
  141. ISet res = SetHelpers.MakeSet(x);
  142. IEnumerator ie = PythonOps.GetEnumerator(y);
  143. while (ie.MoveNext()) {
  144. if (x.__contains__(ie.Current))
  145. res.PrivAdd(ie.Current);
  146. }
  147. return res;
  148. }
  149. public static ISet Difference(ISet x, object y) {
  150. ISet res = SetHelpers.MakeSet(x, x);
  151. IEnumerator ie = PythonOps.GetEnumerator(y);
  152. while (ie.MoveNext()) {
  153. if (res.__contains__(ie.Current)) {
  154. res.PrivRemove(ie.Current);
  155. }
  156. }
  157. return res;
  158. }
  159. public static ISet SymmetricDifference(ISet x, object y) {
  160. SetCollection otherSet = new SetCollection(PythonOps.GetEnumerator(y)); //make a set to deal w/ dups in the enumerator
  161. ISet res = SetHelpers.MakeSet(x, x) as ISet;
  162. Debug.Assert(res != null);
  163. foreach (object o in otherSet) {
  164. if (res.__contains__(o)) {
  165. res.PrivRemove(o);
  166. } else {
  167. res.PrivAdd(o);
  168. }
  169. }
  170. return res;
  171. }
  172. public static ISet Union(ISet x, object y) {
  173. ISet set = SetHelpers.MakeSet(x, x);
  174. IEnumerator ie = PythonOps.GetEnumerator(y);
  175. while (ie.MoveNext()) {
  176. set.PrivAdd(ie.Current);
  177. }
  178. return set;
  179. }
  180. public static bool IsSubset(ISet x, object y) {
  181. ISet set = y as ISet;
  182. if (set == null) {
  183. set = new SetCollection(PythonOps.GetEnumerator(y));
  184. }
  185. return IsSubset(x, set, false);
  186. }
  187. public static bool IsSuperset(ISet x, object y) {
  188. ISet set = y as ISet;
  189. if (set == null) {
  190. set = new SetCollection(PythonOps.GetEnumerator(y));
  191. }
  192. return IsSubset(set, x, false);
  193. }
  194. public static bool IsSubset(ISet x, ISet y, bool strict) {
  195. if (x.Count > y.Count || strict && x.Count == y.Count) {
  196. return false;
  197. }
  198. foreach (object o in x) {
  199. if (!y.__contains__(o)) {
  200. return false;
  201. }
  202. }
  203. return true;
  204. }
  205. public static PythonTuple Reduce(CommonDictionaryStorage items, PythonType type) {
  206. object[] keys = new object[items.Count];
  207. int i = 0;
  208. foreach (object key in items.GetKeys()) {
  209. keys[i++] = key;
  210. }
  211. return PythonTuple.MakeTuple(type, PythonTuple.MakeTuple(List.FromArrayNoCopy(keys)), null);
  212. }
  213. public static bool Equals(ISet x, ISet y, IEqualityComparer comparer) {
  214. if (x.Count != y.Count) {
  215. return false;
  216. }
  217. // optimization when we know the behavior of the comparer
  218. if (comparer is PythonContext.PythonEqualityComparer) {
  219. foreach (object o in x) {
  220. if (!y.__contains__(o)) {
  221. return false;
  222. }
  223. }
  224. return true;
  225. }
  226. // slower comparison using comparer
  227. List yItems = new List(y.GetEnumerator());
  228. foreach (object o in x) {
  229. bool found = false;
  230. for (int i = 0; i < yItems.Count; i++) {
  231. if (comparer.Equals(o, yItems[i])) {
  232. found = true;
  233. yItems.RemoveAt(i);
  234. break;
  235. }
  236. }
  237. if (!found) {
  238. return false;
  239. }
  240. }
  241. return true;
  242. }
  243. }
  244. /// <summary>
  245. /// Mutable set class
  246. /// </summary>
  247. [PythonType("set"), DebuggerDisplay("set, {Count} items", TargetTypeName = "set"), DebuggerTypeProxy(typeof(CollectionDebugProxy))]
  248. public class SetCollection : ISet {
  249. private CommonDictionaryStorage _items;
  250. #region Set contruction
  251. public void __init__() {
  252. clear();
  253. }
  254. public void __init__(object setData) {
  255. CommonDictionaryStorage newStorage = new CommonDictionaryStorage();
  256. IEnumerator ie = PythonOps.GetEnumerator(setData);
  257. while (ie.MoveNext()) {
  258. object current = ie.Current;
  259. newStorage.AddNoLock(current, current);
  260. }
  261. _items = newStorage;
  262. }
  263. public static object __new__(CodeContext/*!*/ context, PythonType cls) {
  264. if (cls == TypeCache.Set) {
  265. return new SetCollection();
  266. }
  267. return cls.CreateInstance(context);
  268. }
  269. public static object __new__(CodeContext/*!*/ context, PythonType cls, object arg) {
  270. return __new__(context, cls);
  271. }
  272. public static object __new__(CodeContext/*!*/ context, PythonType cls, params object[] args\u00F8) {
  273. return __new__(context, cls);
  274. }
  275. public static object __new__(CodeContext/*!*/ context, PythonType cls, [ParamDictionary]IDictionary<object, object> kwArgs, params object[] args\u00F8) {
  276. return __new__(context, cls);
  277. }
  278. public SetCollection() {
  279. _items = new CommonDictionaryStorage();
  280. }
  281. internal SetCollection(object setData) {
  282. Init(setData);
  283. }
  284. internal SetCollection(IEnumerator setData) {
  285. _items = new CommonDictionaryStorage();
  286. while (setData.MoveNext()) {
  287. add(setData.Current);
  288. }
  289. }
  290. private void Init(params object[] o) {
  291. if (o.Length > 1) {
  292. throw PythonOps.TypeError("set expected at most 1 arguments, got {0}", o.Length);
  293. }
  294. _items = new CommonDictionaryStorage();
  295. if (o.Length != 0) {
  296. IEnumerator setData = PythonOps.GetEnumerator(o[0]);
  297. while (setData.MoveNext()) {
  298. add(setData.Current);
  299. }
  300. }
  301. }
  302. public SetCollection copy() {
  303. return new SetCollection(((IEnumerable)this).GetEnumerator());
  304. }
  305. #endregion
  306. #region ISet
  307. public int __len__() {
  308. return Count;
  309. }
  310. public bool __contains__(object value) {
  311. // promote sets to FrozenSets for contains checks (so we get a hash code)
  312. value = SetHelpers.GetHashableSetIfSet(value);
  313. if (_items.Count == 0) {
  314. PythonOps.Hash(DefaultContext.Default, value); // make sure we have a hashable item
  315. }
  316. return _items.Contains(value);
  317. }
  318. public PythonTuple __reduce__() {
  319. return SetHelpers.Reduce(_items, DynamicHelpers.GetPythonTypeFromType(typeof(SetCollection)));
  320. }
  321. void ISet.PrivAdd(object adding) {
  322. add(adding);
  323. }
  324. void ISet.PrivRemove(object removing) {
  325. remove(removing);
  326. }
  327. void ISet.SetData(IEnumerable set) {
  328. _items = new CommonDictionaryStorage();
  329. foreach (object o in set) {
  330. _items.Add(o, o);
  331. }
  332. }
  333. #endregion
  334. #region NonOperator Operations
  335. public bool isdisjoint(object s) {
  336. return SetHelpers.Intersection(this, s).Count == 0;
  337. }
  338. public bool issubset(object set) {
  339. return SetHelpers.IsSubset(this, set);
  340. }
  341. public bool issuperset(object set) {
  342. return SetHelpers.IsSuperset(this, set);
  343. }
  344. public ISet union() {
  345. return SetHelpers.MakeSet(this, this);
  346. }
  347. public ISet union(object s) {
  348. return SetHelpers.Union(this, s);
  349. }
  350. public ISet union([NotNull] params object[] ss) {
  351. ISet res = this;
  352. foreach (object s in ss) {
  353. res = SetHelpers.Union(res, s);
  354. }
  355. return res;
  356. }
  357. public ISet intersection() {
  358. return SetHelpers.MakeSet(this, this);
  359. }
  360. public ISet intersection(object s) {
  361. return SetHelpers.Intersection(this, s);
  362. }
  363. public ISet intersection([NotNull] params object[] ss) {
  364. ISet res = this;
  365. foreach (object s in ss) {
  366. res = SetHelpers.Intersection(res, s);
  367. }
  368. return res;
  369. }
  370. public ISet difference() {
  371. return SetHelpers.MakeSet(this, this);
  372. }
  373. public ISet difference(object s) {
  374. return SetHelpers.Difference(this, s);
  375. }
  376. public ISet difference([NotNull] params object[] ss) {
  377. ISet res = this;
  378. foreach (object s in ss) {
  379. res = SetHelpers.Difference(res, s);
  380. }
  381. return res;
  382. }
  383. public ISet symmetric_difference(object s) {
  384. return SetHelpers.SymmetricDifference(this, s);
  385. }
  386. #endregion
  387. #region Mutating Members
  388. /// <summary>
  389. /// Appends one IEnumerable to an existing set
  390. /// </summary>
  391. /// <param name="s"></param>
  392. public void update(object s) {
  393. if (Object.ReferenceEquals(s, this)) {
  394. return;
  395. }
  396. IEnumerator ie = PythonOps.GetEnumerator(s);
  397. while (ie.MoveNext()) {
  398. add(ie.Current);
  399. }
  400. }
  401. /// <summary>
  402. /// Appends one or more IEnumerables to an existing set
  403. /// </summary>
  404. public void update([NotNull] params object[] ss) {
  405. foreach (object s in ss) {
  406. update(s);
  407. }
  408. }
  409. public void add(object o) {
  410. _items.Add(o, o);
  411. }
  412. public void intersection_update(object s) {
  413. SetCollection set = intersection(s) as SetCollection;
  414. _items = set._items;
  415. }
  416. public void intersection_update([NotNull] params object[] ss) {
  417. foreach (object s in ss) {
  418. intersection_update(s);
  419. }
  420. }
  421. public void difference_update(object s) {
  422. SetCollection set = new SetCollection(PythonOps.GetEnumerator(s));
  423. foreach (object o in set) {
  424. if (__contains__(o)) {
  425. remove(o);
  426. }
  427. }
  428. }
  429. public void difference_update([NotNull] params object[] ss) {
  430. foreach (object s in ss) {
  431. difference_update(s);
  432. }
  433. }
  434. public void symmetric_difference_update(object s) {
  435. SetCollection set = new SetCollection(PythonOps.GetEnumerator(s));
  436. foreach (object o in set) {
  437. if (__contains__(o)) {
  438. remove(o);
  439. } else {
  440. add(o);
  441. }
  442. }
  443. }
  444. public void remove([NotNull]SetCollection o) {
  445. var set = SetHelpers.GetHashableSetIfSet(o);
  446. if (!_items.RemoveAlwaysHash(set)) {
  447. throw PythonOps.KeyError(o);
  448. }
  449. }
  450. public void remove(object o) {
  451. if (!_items.RemoveAlwaysHash(o)) {
  452. throw PythonOps.KeyError(o);
  453. }
  454. }
  455. public void discard(object o) {
  456. o = SetHelpers.GetHashableSetIfSet(o);
  457. _items.Remove(o);
  458. }
  459. public object pop() {
  460. foreach (object o in _items.GetKeys()) {
  461. _items.Remove(o);
  462. return o;
  463. }
  464. throw PythonOps.KeyError("pop from an empty set");
  465. }
  466. public void clear() {
  467. _items.Clear();
  468. }
  469. #endregion
  470. #region Operators
  471. [SpecialName]
  472. public SetCollection InPlaceBitwiseAnd(object s) {
  473. ISet set = s as ISet;
  474. if (set == null) {
  475. throw PythonOps.TypeError("unsupported operand type(s) for &=: '{0}' and '{1}'", PythonTypeOps.GetName(s), PythonTypeOps.GetName(this));
  476. }
  477. intersection_update(set);
  478. return this;
  479. }
  480. [SpecialName]
  481. public SetCollection InPlaceBitwiseOr(object s) {
  482. ISet set = s as ISet;
  483. if (set == null) {
  484. throw PythonOps.TypeError("unsupported operand type(s) for |=: '{0}' and '{1}'", PythonTypeOps.GetName(s), PythonTypeOps.GetName(this));
  485. }
  486. update(set);
  487. return this;
  488. }
  489. [SpecialName]
  490. public SetCollection InPlaceSubtract(object s) {
  491. ISet set = s as ISet;
  492. if (set == null) {
  493. throw PythonOps.TypeError("unsupported operand type(s) for -=: '{0}' and '{1}'", PythonTypeOps.GetName(s), PythonTypeOps.GetName(this));
  494. }
  495. difference_update(set);
  496. return this;
  497. }
  498. [SpecialName]
  499. public SetCollection InPlaceExclusiveOr(object s) {
  500. ISet set = s as ISet;
  501. if (set == null) {
  502. throw PythonOps.TypeError("unsupported operand type(s) for ^=: '{0}' and '{1}'", PythonTypeOps.GetName(s), PythonTypeOps.GetName(this));
  503. }
  504. symmetric_difference_update(set);
  505. return this;
  506. }
  507. public static object operator &(ISet y, SetCollection x) {
  508. return y.intersection(x);
  509. }
  510. public static object operator |(ISet y, SetCollection x) {
  511. return y.union(x);
  512. }
  513. public static object operator ^(ISet y, SetCollection x) {
  514. return y.symmetric_difference(x);
  515. }
  516. public static object operator -(ISet y, SetCollection x) {
  517. return y.difference(x);
  518. }
  519. public static ISet operator &(SetCollection x, ISet y) {
  520. return x.intersection(y);
  521. }
  522. public static ISet operator |(SetCollection x, ISet y) {
  523. return x.union(y);
  524. }
  525. public static ISet operator ^(SetCollection x, ISet y) {
  526. return x.symmetric_difference(y);
  527. }
  528. public static ISet operator -(SetCollection x, ISet y) {
  529. return x.difference(y);
  530. }
  531. #endregion
  532. #region IValueEquality Members
  533. #if CLR2
  534. int IValueEquality.GetValueHashCode() {
  535. throw PythonOps.TypeError("set objects are unhashable");
  536. }
  537. bool IValueEquality.ValueEquals(object o) {
  538. return __eq__(o);
  539. }
  540. #endif
  541. #endregion
  542. #region IStructuralEquatable Members
  543. public const object __hash__ = null;
  544. int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) {
  545. if (CompareUtil.Check(this)) {
  546. return 0;
  547. }
  548. int res;
  549. CompareUtil.Push(this);
  550. try {
  551. res = ((IStructuralEquatable)new FrozenSetCollection(this)).GetHashCode(comparer);
  552. } finally {
  553. CompareUtil.Pop(this);
  554. }
  555. return res;
  556. }
  557. bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) {
  558. ISet set = other as ISet;
  559. if (set != null) {
  560. return SetHelpers.Equals(this, set, comparer);
  561. }
  562. return false;
  563. }
  564. // default conversion of protocol methods only allows our specific type for equality,
  565. // sets can do __eq__ / __ne__ against any type though. That's why we have a seperate
  566. // __eq__ / __ne__ here.
  567. public bool __eq__(object other) {
  568. ISet set = other as ISet;
  569. if (set != null) {
  570. if (set.Count != Count) {
  571. return false;
  572. }
  573. return issubset(set);
  574. }
  575. return false;
  576. }
  577. public bool __ne__(object other) {
  578. return !__eq__(other);
  579. }
  580. #endregion
  581. #region IRichComparable
  582. public static bool operator >(SetCollection self, object other) {
  583. ISet s = other as ISet;
  584. if (s == null) {
  585. throw PythonOps.TypeError("can only compare to a set");
  586. }
  587. return SetHelpers.IsSubset(s, self, true);
  588. }
  589. public static bool operator <(SetCollection self, object other) {
  590. ISet s = other as ISet;
  591. if (s == null) {
  592. throw PythonOps.TypeError("can only compare to a set");
  593. }
  594. return SetHelpers.IsSubset(self, s, true);
  595. }
  596. public static bool operator >=(SetCollection self, object other) {
  597. ISet s = other as ISet;
  598. if (s == null) {
  599. throw PythonOps.TypeError("can only compare to a set");
  600. }
  601. return SetHelpers.IsSubset(s, self, false);
  602. }
  603. public static bool operator <=(SetCollection self, object other) {
  604. ISet s = other as ISet;
  605. if (s == null) {
  606. throw PythonOps.TypeError("can only compare to a set");
  607. }
  608. return SetHelpers.IsSubset(self, s, false);
  609. }
  610. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "o")]
  611. [SpecialName]
  612. public int Compare(object o) {
  613. throw PythonOps.TypeError("cannot compare sets using cmp()");
  614. }
  615. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
  616. public int __cmp__(object o) {
  617. throw PythonOps.TypeError("cannot compare sets using cmp()");
  618. }
  619. #endregion
  620. #region IEnumerable Members
  621. IEnumerator IEnumerable.GetEnumerator() {
  622. return new SetIterator(_items, true);
  623. }
  624. #endregion
  625. #region IEnumerable<object> Members
  626. IEnumerator<object> IEnumerable<object>.GetEnumerator() {
  627. return new SetIterator(_items, true);
  628. }
  629. #endregion
  630. #region ICodeFormattable Members
  631. public virtual string/*!*/ __repr__(CodeContext/*!*/ context) {
  632. return SetHelpers.SetToString(context, this, _items);
  633. }
  634. #endregion
  635. #region ICollection Members
  636. void ICollection.CopyTo(Array array, int index) {
  637. int i = 0;
  638. foreach (object o in this) {
  639. array.SetValue(o, index + i++);
  640. }
  641. }
  642. public int Count {
  643. [PythonHidden]
  644. get { return _items.Count; }
  645. }
  646. bool ICollection.IsSynchronized {
  647. get { return false; }
  648. }
  649. object ICollection.SyncRoot {
  650. get { return this; }
  651. }
  652. #endregion
  653. }
  654. /// <summary>
  655. /// Immutable set class
  656. /// </summary>
  657. [PythonType("frozenset"), DebuggerDisplay("frozenset, {Count} items", TargetTypeName = "frozenset"), DebuggerTypeProxy(typeof(CollectionDebugProxy))]
  658. public class FrozenSetCollection : ISet {
  659. internal static readonly FrozenSetCollection EMPTY = new FrozenSetCollection();
  660. private CommonDictionaryStorage _items;
  661. private HashCache _hashCache;
  662. #region Set Construction
  663. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "o")]
  664. public void __init__(params object[] o) {
  665. // nop
  666. }
  667. public static FrozenSetCollection __new__(CodeContext context, object cls) {
  668. if (cls == TypeCache.FrozenSet) {
  669. return EMPTY;
  670. } else {
  671. PythonType dt = cls as PythonType;
  672. object res = dt.CreateInstance(context);
  673. FrozenSetCollection fs = res as FrozenSetCollection;
  674. if (fs == null) {
  675. throw PythonOps.TypeError("{0} is not a subclass of frozenset", res);
  676. }
  677. return fs;
  678. }
  679. }
  680. public static FrozenSetCollection __new__(CodeContext context, object cls, object setData) {
  681. if (cls == TypeCache.FrozenSet) {
  682. FrozenSetCollection fs = setData as FrozenSetCollection;
  683. if (fs != null) {
  684. // constructing frozen set from frozen set, we return the original frozen set.
  685. return fs;
  686. }
  687. fs = FrozenSetCollection.Make(setData);
  688. return fs;
  689. } else {
  690. object res = ((PythonType)cls).CreateInstance(context, setData);
  691. FrozenSetCollection fs = res as FrozenSetCollection;
  692. if (fs == null) {
  693. throw PythonOps.TypeError("{0} is not a subclass of frozenset", res);
  694. }
  695. return fs;
  696. }
  697. }
  698. internal static FrozenSetCollection Make(object setData) {
  699. FrozenSetCollection fs = setData as FrozenSetCollection;
  700. if (fs != null) {
  701. // constructing frozen set from frozen set, we return the original frozen set.
  702. return fs;
  703. }
  704. CommonDictionaryStorage items = ListToDictionary(setData);
  705. if (items.Count == 0) {
  706. fs = EMPTY;
  707. } else {
  708. fs = new FrozenSetCollection(items);
  709. }
  710. return fs;
  711. }
  712. private static CommonDictionaryStorage ListToDictionary(object set) {
  713. IEnumerator setData = PythonOps.GetEnumerator(set);
  714. CommonDictionaryStorage items = new CommonDictionaryStorage();
  715. while (setData.MoveNext()) {
  716. object o = setData.Current;
  717. items.Add(o, o);
  718. }
  719. return items;
  720. }
  721. public FrozenSetCollection()
  722. : this(new CommonDictionaryStorage()) {
  723. }
  724. private FrozenSetCollection(CommonDictionaryStorage set) {
  725. _items = set;
  726. }
  727. protected FrozenSetCollection(object set)
  728. : this(ListToDictionary(set)) {
  729. }
  730. internal FrozenSetCollection(ISet set)
  731. : this((object)set) {
  732. }
  733. public FrozenSetCollection copy() {
  734. // Python behavior: If we're a non-derived frozen set, we return ourselves.
  735. // If we're a derived frozen set we make a new set of our type that contains our
  736. // contents.
  737. if (this.GetType() == typeof(FrozenSetCollection)) {
  738. return this;
  739. }
  740. FrozenSetCollection set = (FrozenSetCollection)SetHelpers.MakeSet(this, this);
  741. return set;
  742. }
  743. #endregion
  744. #region ISet
  745. public int __len__() {
  746. return Count;
  747. }
  748. public bool __contains__(object value) {
  749. // promote sets to FrozenSets for contains checks (so we get a hash code)
  750. value = SetHelpers.GetHashableSetIfSet(value);
  751. if (_items.Count == 0) {
  752. PythonOps.Hash(DefaultContext.Default, value); // make sure we have a hashable item
  753. }
  754. return _items.Contains(value);
  755. }
  756. public PythonTuple __reduce__() {
  757. return SetHelpers.Reduce(_items, DynamicHelpers.GetPythonTypeFromType(typeof(FrozenSetCollection)));
  758. }
  759. void ISet.PrivAdd(object adding) {
  760. PythonOps.Hash(DefaultContext.Default, adding);// make sure we're hashable
  761. _items.Add(adding, adding);
  762. }
  763. void ISet.PrivRemove(object removing) {
  764. PythonOps.Hash(DefaultContext.Default, removing);// make sure we're hashable
  765. _items.Remove(removing);
  766. }
  767. void ISet.SetData(IEnumerable set) {
  768. _items = new CommonDictionaryStorage();
  769. foreach (object o in set) {
  770. _items.Add(o, o);
  771. }
  772. }
  773. #endregion
  774. #region NonOperator Operations
  775. public bool isdisjoint(object s) {
  776. return SetHelpers.Intersection(this, s).Count == 0;
  777. }
  778. public bool issubset(object set) {
  779. return SetHelpers.IsSubset(this, set);
  780. }
  781. public bool issuperset(object set) {
  782. return SetHelpers.IsSuperset(this, set);
  783. }
  784. public ISet union() {
  785. return SetHelpers.MakeSet(this, this);
  786. }
  787. public ISet union(object s) {
  788. return SetHelpers.Union(this, s);
  789. }
  790. public ISet union([NotNull] params object[] ss) {
  791. ISet res = this;
  792. foreach (object s in ss) {
  793. res = SetHelpers.Union(res, s);
  794. }
  795. return res;
  796. }
  797. public ISet intersection() {
  798. return SetHelpers.MakeSet(this, this);
  799. }
  800. public ISet intersection(object s) {
  801. return SetHelpers.Intersection(this, s);
  802. }
  803. public ISet intersection([NotNull] params object[] ss) {
  804. ISet res = this;
  805. foreach (object s in ss) {
  806. res = SetHelpers.Intersection(res, s);
  807. }
  808. return res;
  809. }
  810. public ISet difference() {
  811. return SetHelpers.MakeSet(this, this);
  812. }
  813. public ISet difference(object s) {
  814. return SetHelpers.Difference(this, s);
  815. }
  816. public ISet difference([NotNull] params object[] ss) {
  817. ISet res = this;
  818. foreach (object s in ss) {
  819. res = SetHelpers.Difference(res, s);
  820. }
  821. return res;
  822. }
  823. public ISet symmetric_difference(object s) {
  824. return SetHelpers.SymmetricDifference(this, s);
  825. }
  826. #endregion
  827. #region Operators
  828. public static object operator &(ISet y, FrozenSetCollection x) {
  829. return y.intersection(x);
  830. }
  831. public static object operator |(ISet y, FrozenSetCollection x) {
  832. return y.intersection(x);
  833. }
  834. public static object operator ^(ISet y, FrozenSetCollection x) {
  835. return y.intersection(x);
  836. }
  837. public static object operator -(ISet y, FrozenSetCollection x) {
  838. return y.difference(x);
  839. }
  840. public static ISet operator &(FrozenSetCollection x, ISet y) {
  841. return x.intersection(y);
  842. }
  843. public static ISet operator |(FrozenSetCollection x, ISet y) {
  844. return x.union(y);
  845. }
  846. public static ISet operator ^(FrozenSetCollection x, ISet y) {
  847. return x.symmetric_difference(y);
  848. }
  849. public static ISet operator -(FrozenSetCollection x, ISet y) {
  850. return x.difference(y);
  851. }
  852. #endregion
  853. #region IStructuralEquatable Members
  854. private sealed class HashCache {
  855. internal readonly int HashCode;
  856. internal readonly IEqualityComparer Comparer;
  857. internal HashCache(int hashCode, IEqualityComparer comparer) {
  858. HashCode = hashCode;
  859. Comparer = comparer;
  860. }
  861. }
  862. private int CalculateHashCode(IEqualityComparer/*!*/ comparer) {
  863. Assert.NotNull(comparer);
  864. HashCache curHashCache = _hashCache;
  865. if (curHashCache != null && object.ReferenceEquals(comparer, curHashCache.Comparer)) {
  866. return curHashCache.HashCode;
  867. }
  868. // hash code needs be stable across collections (even if keys are
  869. // added in different order) and needs to be fairly collision free.
  870. int[] hash_codes = new int[_items.Count];
  871. int i = 0;
  872. foreach (object o in _items.GetKeys()) {
  873. hash_codes[i++] = comparer.GetHashCode(o);
  874. }
  875. Array.Sort(hash_codes);
  876. int hash1 = 6551;
  877. int hash2 = hash1;
  878. for (i = 0; i < hash_codes.Length; i += 2) {
  879. hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ hash_codes[i];
  880. if (i == hash_codes.Length - 1) {
  881. break;
  882. }
  883. hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ hash_codes[i + 1];
  884. }
  885. hash1 += hash2 * 1566083941;
  886. _hashCache = new HashCache(hash1, comparer);
  887. return hash1;
  888. }
  889. int IStructuralEquatable.GetHashCode(IEqualityComparer/*!*/ comparer) {
  890. return CalculateHashCode(comparer);
  891. }
  892. bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) {
  893. ISet set = other as ISet;
  894. if (set != null) {
  895. return SetHelpers.Equals(this, set, comparer);
  896. }
  897. return false;
  898. }
  899. // default conversion of protocol methods only allows our specific type for equality,
  900. // sets can do __eq__ / __ne__ against any type though. That's why we have a seperate
  901. // __eq__ / __ne__ here.
  902. public bool __eq__(object other) {
  903. ISet set = other as ISet;
  904. if (set != null) {
  905. if (set.Count != Count) {
  906. return false;
  907. }
  908. return issubset(set);
  909. }
  910. return false;
  911. }
  912. public bool __ne__(object other) {
  913. return !__eq__(other);
  914. }
  915. #endregion
  916. #region IValueEquality Members
  917. #if CLR2
  918. int IValueEquality.GetValueHashCode() {
  919. return CalculateHashCode(DefaultContext.DefaultPythonContext.EqualityComparerNonGeneric);
  920. }
  921. bool IValueEquality.ValueEquals(object o) {
  922. return __eq__(o);
  923. }
  924. #endif
  925. #endregion
  926. #region IRichComparable
  927. public static bool operator >(FrozenSetCollection self, object other) {
  928. ISet s = other as ISet;
  929. if (s == null) {
  930. throw PythonOps.TypeError("can only compare to a set");
  931. }
  932. return SetHelpers.IsSubset(s, self, true);
  933. }
  934. public static bool operator <(FrozenSetCollection self, object other) {
  935. ISet s = other as ISet;
  936. if (s == null) {
  937. throw PythonOps.TypeError("can only compare to a set");
  938. }
  939. return SetHelpers.IsSubset(self, s, true);
  940. }
  941. public static bool operator >=(FrozenSetCollection self, object other) {
  942. ISet s = other as ISet;
  943. if (s == null) {
  944. throw PythonOps.TypeError("can only compare to a set");
  945. }
  946. return SetHelpers.IsSubset(s, self, false);
  947. }
  948. public static bool operator <=(FrozenSetCollection self, object other) {
  949. ISet s = other as ISet;
  950. if (s == null) {
  951. throw PythonOps.TypeError("can only compare to a set");
  952. }
  953. return SetHelpers.IsSubset(self, s, false);
  954. }
  955. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "o")]
  956. [SpecialName]
  957. public int Compare(object o) {
  958. throw PythonOps.TypeError("cannot compare sets using cmp()");
  959. }
  960. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
  961. public int __cmp__(object o) {
  962. throw PythonOps.TypeError("cannot compare sets using cmp()");
  963. }
  964. #endregion
  965. #region IEnumerable Members
  966. IEnumerator IEnumerable.GetEnumerator() {
  967. return new SetIterator(_items, false);
  968. }
  969. #endregion
  970. #region IEnumerable<object> Members
  971. IEnumerator<object> IEnumerable<object>.GetEnumerator() {
  972. return new SetIterator(_items, false);
  973. }
  974. #endregion
  975. #region ICodeFormattable Members
  976. public virtual string/*!*/ __repr__(CodeContext/*!*/ context) {
  977. return SetHelpers.SetToString(context, this, _items);
  978. }
  979. #endregion
  980. #region ICollection Members
  981. void ICollection.CopyTo(Array array, int index) {
  982. int i = 0;
  983. foreach (object o in this) {
  984. array.SetValue(o, index + i++);
  985. }
  986. }
  987. public int Count {
  988. [PythonHidden]
  989. get { return _items.Count; }
  990. }
  991. bool ICollection.IsSynchronized {
  992. get { return false; }
  993. }
  994. object ICollection.SyncRoot {
  995. get { return this; }
  996. }
  997. #endregion
  998. }
  999. /// <summary>
  1000. /// Iterator over sets
  1001. /// </summary>
  1002. [PythonType("setiterator")]
  1003. public sealed class SetIterator : IEnumerable, IEnumerable<object>, IEnumerator, IEnumerator<object> {
  1004. private readonly CommonDictionaryStorage _items;
  1005. private readonly IEnumerator<object> _enumerator;
  1006. private readonly int _version;
  1007. internal SetIterator(CommonDictionaryStorage items, bool mutable) {
  1008. _items = items;
  1009. if (mutable) {
  1010. lock (items) {
  1011. _version = _items.Version;
  1012. _enumerator = items.GetKeys().GetEnumerator();
  1013. }
  1014. } else {
  1015. _version = _items.Version;
  1016. _enumerator = items.GetKeys().GetEnumerator();
  1017. }
  1018. }
  1019. #region IDisposable Members
  1020. [PythonHidden]
  1021. public void Dispose() {
  1022. _enumerator.Dispose();
  1023. }
  1024. #endregion
  1025. #region IEnumerator Members
  1026. public object Current {
  1027. [PythonHidden]
  1028. get {
  1029. if (_items.Version != _version) {
  1030. throw PythonOps.RuntimeError("set changed during iteration");
  1031. }
  1032. return _enumerator.Current;
  1033. }
  1034. }
  1035. [PythonHidden]
  1036. public bool MoveNext() {
  1037. return _enumerator.MoveNext();
  1038. }
  1039. [PythonHidden]
  1040. public void Reset() {
  1041. _enumerator.Reset();
  1042. }
  1043. #endregion
  1044. #region IEnumerable Members
  1045. [PythonHidden]
  1046. public IEnumerator GetEnumerator() {
  1047. return this;
  1048. }
  1049. #endregion
  1050. #region IEnumerable<object> Members
  1051. IEnumerator<object> IEnumerable<object>.GetEnumerator() {
  1052. return this;
  1053. }
  1054. #endregion
  1055. }
  1056. }