PageRenderTime 56ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/DICK.B1/IronPython/Runtime/PythonTuple.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 690 lines | 515 code | 144 blank | 31 comment | 96 complexity | b6278beef6bee7f0437e10c212e6d641 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.InteropServices;
  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. #if CLR2
  27. using Microsoft.Scripting.Math;
  28. #else
  29. using System.Numerics;
  30. #endif
  31. namespace IronPython.Runtime {
  32. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
  33. [PythonType("tuple"), Serializable, DebuggerTypeProxy(typeof(CollectionDebugProxy)), DebuggerDisplay("tuple, {Count} items")]
  34. public class PythonTuple : ICollection, IEnumerable, IEnumerable<object>, IList, IList<object>, ICodeFormattable,
  35. #if CLR2
  36. IValueEquality,
  37. #endif
  38. IStructuralEquatable, IStructuralComparable
  39. {
  40. internal readonly object[] _data;
  41. internal static readonly PythonTuple EMPTY = new PythonTuple();
  42. public PythonTuple(object o) {
  43. this._data = MakeItems(o);
  44. }
  45. protected PythonTuple(object[] items) {
  46. this._data = items;
  47. }
  48. public PythonTuple() {
  49. this._data = ArrayUtils.EmptyObjects;
  50. }
  51. internal PythonTuple(PythonTuple other, object o) {
  52. this._data = other.Expand(o);
  53. }
  54. #region Python Constructors
  55. // Tuples are immutable so their initialization happens in __new__
  56. // They also explicitly implement __new__ so they can perform the
  57. // appropriate caching.
  58. public static PythonTuple __new__(CodeContext context, PythonType cls) {
  59. if (cls == TypeCache.PythonTuple) {
  60. return EMPTY;
  61. } else {
  62. PythonTuple tupObj = cls.CreateInstance(context) as PythonTuple;
  63. if (tupObj == null) throw PythonOps.TypeError("{0} is not a subclass of tuple", cls);
  64. return tupObj;
  65. }
  66. }
  67. public static PythonTuple __new__(CodeContext context, PythonType cls, object sequence) {
  68. if (sequence == null) throw PythonOps.TypeError("iteration over a non-sequence");
  69. if (cls == TypeCache.PythonTuple) {
  70. if (sequence.GetType() == typeof(PythonTuple)) return (PythonTuple)sequence;
  71. return new PythonTuple(MakeItems(sequence));
  72. } else {
  73. PythonTuple tupObj = cls.CreateInstance(context, sequence) as PythonTuple;
  74. if (tupObj == null) throw PythonOps.TypeError("{0} is not a subclass of tuple", cls);
  75. return tupObj;
  76. }
  77. }
  78. #endregion
  79. #region Python 2.6 Methods
  80. public int index(object obj, object start) {
  81. return index(obj, Converter.ConvertToIndex(start), _data.Length);
  82. }
  83. public int index(object obj, [DefaultParameterValue(0)]int start) {
  84. return index(obj, start, _data.Length);
  85. }
  86. public int index(object obj, object start, object end) {
  87. return index(obj, Converter.ConvertToIndex(start), Converter.ConvertToIndex(end));
  88. }
  89. public int index(object obj, int start, int end) {
  90. start = PythonOps.FixSliceIndex(start, _data.Length);
  91. end = PythonOps.FixSliceIndex(end, _data.Length);
  92. for (int i = start; i < end; i++) {
  93. if (PythonOps.EqualRetBool(obj, _data[i])) {
  94. return i;
  95. }
  96. }
  97. throw PythonOps.ValueError("tuple.index(x): x not in list");
  98. }
  99. public int count(object obj) {
  100. int cnt = 0;
  101. foreach (object elem in _data) {
  102. if (PythonOps.EqualRetBool(obj, elem)) {
  103. cnt++;
  104. }
  105. }
  106. return cnt;
  107. }
  108. #endregion
  109. internal static PythonTuple Make(object o) {
  110. if (o is PythonTuple) return (PythonTuple)o;
  111. return new PythonTuple(MakeItems(o));
  112. }
  113. internal static PythonTuple MakeTuple(params object[] items) {
  114. if (items.Length == 0) return EMPTY;
  115. return new PythonTuple(items);
  116. }
  117. private static object[] MakeItems(object o) {
  118. object[] arr;
  119. if (o is PythonTuple) {
  120. return ((PythonTuple)o)._data;
  121. } else if (o is string) {
  122. string s = (string)o;
  123. object[] res = new object[s.Length];
  124. for (int i = 0; i < res.Length; i++) {
  125. res[i] = ScriptingRuntimeHelpers.CharToString(s[i]);
  126. }
  127. return res;
  128. } else if (o is List) {
  129. return ((List)o).GetObjectArray();
  130. } else if ((arr = o as object[])!=null) {
  131. return ArrayOps.CopyArray(arr, arr.Length);
  132. } else {
  133. PerfTrack.NoteEvent(PerfTrack.Categories.OverAllocate, "TupleOA: " + PythonTypeOps.GetName(o));
  134. List<object> l = new List<object>();
  135. IEnumerator i = PythonOps.GetEnumerator(o);
  136. while (i.MoveNext()) {
  137. l.Add(i.Current);
  138. }
  139. return l.ToArray();
  140. }
  141. }
  142. /// <summary>
  143. /// Return a copy of this tuple's data array.
  144. /// </summary>
  145. internal object[] ToArray() {
  146. return ArrayOps.CopyArray(_data, _data.Length);
  147. }
  148. #region ISequence Members
  149. public virtual int __len__() {
  150. return _data.Length;
  151. }
  152. public virtual object this[int index] {
  153. get {
  154. return _data[PythonOps.FixIndex(index, _data.Length)];
  155. }
  156. }
  157. public virtual object this[object index] {
  158. get {
  159. return this[Converter.ConvertToIndex(index)];
  160. }
  161. }
  162. public virtual object this[BigInteger index] {
  163. get {
  164. return this[(int)index];
  165. }
  166. }
  167. public virtual object __getslice__(int start, int stop) {
  168. Slice.FixSliceArguments(_data.Length, ref start, ref stop);
  169. return MakeTuple(ArrayOps.GetSlice(_data, start, stop));
  170. }
  171. public virtual object this[Slice slice] {
  172. get {
  173. return MakeTuple(ArrayOps.GetSlice(_data, slice));
  174. }
  175. }
  176. #endregion
  177. #region binary operators
  178. public static PythonTuple operator +([NotNull]PythonTuple x, [NotNull]PythonTuple y) {
  179. return MakeTuple(ArrayOps.Add(x._data, x._data.Length, y._data, y._data.Length));
  180. }
  181. private static PythonTuple MultiplyWorker(PythonTuple self, int count) {
  182. if (count <= 0) {
  183. return EMPTY;
  184. } else if (count == 1 && self.GetType() == typeof(PythonTuple)) {
  185. return self;
  186. }
  187. return MakeTuple(ArrayOps.Multiply(self._data, self._data.Length, count));
  188. }
  189. public static PythonTuple operator *(PythonTuple x, int n) {
  190. return MultiplyWorker(x, n);
  191. }
  192. public static PythonTuple operator *(int n, PythonTuple x) {
  193. return MultiplyWorker(x, n);
  194. }
  195. public static object operator *([NotNull]PythonTuple self, [NotNull]Index count) {
  196. return PythonOps.MultiplySequence<PythonTuple>(MultiplyWorker, self, count, true);
  197. }
  198. public static object operator *([NotNull]Index count, [NotNull]PythonTuple self) {
  199. return PythonOps.MultiplySequence<PythonTuple>(MultiplyWorker, self, count, false);
  200. }
  201. public static object operator *([NotNull]PythonTuple self, object count) {
  202. int index;
  203. if (Converter.TryConvertToIndex(count, out index)) {
  204. return self * index;
  205. }
  206. throw PythonOps.TypeErrorForUnIndexableObject(count);
  207. }
  208. public static object operator *(object count, [NotNull]PythonTuple self) {
  209. int index;
  210. if (Converter.TryConvertToIndex(count, out index)) {
  211. return index * self;
  212. }
  213. throw PythonOps.TypeErrorForUnIndexableObject(count);
  214. }
  215. #endregion
  216. #region ICollection Members
  217. bool ICollection.IsSynchronized {
  218. get { return false; }
  219. }
  220. public int Count {
  221. [PythonHidden]
  222. get { return _data.Length; }
  223. }
  224. [PythonHidden]
  225. public void CopyTo(Array array, int index) {
  226. Array.Copy(_data, 0, array, index, _data.Length);
  227. }
  228. object ICollection.SyncRoot {
  229. get {
  230. return this;
  231. }
  232. }
  233. #endregion
  234. public virtual IEnumerator __iter__() {
  235. return new TupleEnumerator(this);
  236. }
  237. #region IEnumerable Members
  238. [PythonHidden]
  239. public IEnumerator GetEnumerator() {
  240. return __iter__();
  241. }
  242. #endregion
  243. private object[] Expand(object value) {
  244. object[] args;
  245. int length = _data.Length;
  246. if (value == null)
  247. args = new object[length];
  248. else
  249. args = new object[length + 1];
  250. for (int i = 0; i < length; i++) {
  251. args[i] = _data[i];
  252. }
  253. if (value != null) {
  254. args[length] = value;
  255. }
  256. return args;
  257. }
  258. public object __getnewargs__() {
  259. // Call "new Tuple()" to force result to be a Tuple (otherwise, it could possibly be a Tuple subclass)
  260. return PythonTuple.MakeTuple(new PythonTuple(this));
  261. }
  262. #region IEnumerable<object> Members
  263. IEnumerator<object> IEnumerable<object>.GetEnumerator() {
  264. return new TupleEnumerator(this);
  265. }
  266. #endregion
  267. #region IList<object> Members
  268. [PythonHidden]
  269. public int IndexOf(object item) {
  270. for (int i = 0; i < Count; i++) {
  271. if (PythonOps.EqualRetBool(this[i], item)) return i;
  272. }
  273. return -1;
  274. }
  275. void IList<object>.Insert(int index, object item) {
  276. throw new InvalidOperationException("Tuple is readonly");
  277. }
  278. void IList<object>.RemoveAt(int index) {
  279. throw new InvalidOperationException("Tuple is readonly");
  280. }
  281. object IList<object>.this[int index] {
  282. get {
  283. return this[index];
  284. }
  285. set {
  286. throw new InvalidOperationException("Tuple is readonly");
  287. }
  288. }
  289. #endregion
  290. #region ICollection<object> Members
  291. void ICollection<object>.Add(object item) {
  292. throw new InvalidOperationException("Tuple is readonly");
  293. }
  294. void ICollection<object>.Clear() {
  295. throw new InvalidOperationException("Tuple is readonly");
  296. }
  297. [PythonHidden]
  298. public bool Contains(object item) {
  299. for (int i = 0; i < _data.Length; i++) {
  300. if (PythonOps.EqualRetBool(_data[i], item)) {
  301. return true;
  302. }
  303. }
  304. return false;
  305. }
  306. [PythonHidden]
  307. public void CopyTo(object[] array, int arrayIndex) {
  308. for (int i = 0; i < Count; i++) {
  309. array[arrayIndex + i] = this[i];
  310. }
  311. }
  312. bool ICollection<object>.IsReadOnly {
  313. get { return true; }
  314. }
  315. bool ICollection<object>.Remove(object item) {
  316. throw new InvalidOperationException("Tuple is readonly");
  317. }
  318. #endregion
  319. #region Rich Comparison Members
  320. internal int CompareTo(PythonTuple other) {
  321. return PythonOps.CompareArrays(_data, _data.Length, other._data, other._data.Length);
  322. }
  323. public static bool operator >([NotNull]PythonTuple self, [NotNull]PythonTuple other) {
  324. return self.CompareTo(other) > 0;
  325. }
  326. public static bool operator <([NotNull]PythonTuple self, [NotNull]PythonTuple other) {
  327. return self.CompareTo(other) < 0;
  328. }
  329. public static bool operator >=([NotNull]PythonTuple self, [NotNull]PythonTuple other) {
  330. return self.CompareTo(other) >= 0;
  331. }
  332. public static bool operator <=([NotNull]PythonTuple self, [NotNull]PythonTuple other) {
  333. return self.CompareTo(other) <= 0;
  334. }
  335. #endregion
  336. #region IStructuralComparable Members
  337. int IStructuralComparable.CompareTo(object obj, IComparer comparer) {
  338. PythonTuple other = obj as PythonTuple;
  339. if (other == null) {
  340. throw new ArgumentException("expected tuple");
  341. }
  342. return PythonOps.CompareArrays(_data, _data.Length, other._data, other._data.Length, comparer);
  343. }
  344. #endregion
  345. public override bool Equals(object obj) {
  346. if (!Object.ReferenceEquals(this, obj)) {
  347. PythonTuple other = obj as PythonTuple;
  348. if (other == null || _data.Length != other._data.Length) {
  349. return false;
  350. }
  351. for (int i = 0; i < _data.Length; i++) {
  352. object obj1 = this[i], obj2 = other[i];
  353. if (Object.ReferenceEquals(obj1, obj2)) {
  354. continue;
  355. } else if (obj1 != null) {
  356. if (!obj1.Equals(obj2)) {
  357. return false;
  358. }
  359. } else {
  360. return false;
  361. }
  362. }
  363. }
  364. return true;
  365. }
  366. public override int GetHashCode() {
  367. int hash1 = 6551;
  368. int hash2 = hash1;
  369. for (int i = 0; i < _data.Length; i += 2) {
  370. hash1 = ((hash1 << 27) + ((hash2 + 1) << 1) + (hash1 >> 5)) ^ _data[i].GetHashCode();
  371. if (i == _data.Length - 1) {
  372. break;
  373. }
  374. hash2 = ((hash2 << 5) + ((hash1 - 1) >> 1) + (hash2 >> 27)) ^ _data[i + 1].GetHashCode();
  375. }
  376. return hash1 + (hash2 * 1566083941);
  377. }
  378. private int GetHashCode(HashDelegate dlg) {
  379. int hash1 = 6551;
  380. int hash2 = hash1;
  381. for (int i = 0; i < _data.Length; i += 2) {
  382. hash1 = ((hash1 << 27) + ((hash2 + 1) << 1) + (hash1 >> 5)) ^ dlg(_data[i], ref dlg);
  383. if (i == _data.Length - 1) {
  384. break;
  385. }
  386. hash2 = ((hash2 << 5) + ((hash1 - 1) >> 1) + (hash2 >> 27)) ^ dlg(_data[i + 1], ref dlg);
  387. }
  388. return hash1 + (hash2 * 1566083941);
  389. }
  390. private int GetHashCode(IEqualityComparer comparer) {
  391. int hash1 = 6551;
  392. int hash2 = hash1;
  393. for (int i = 0; i < _data.Length; i += 2) {
  394. hash1 = ((hash1 << 27) + ((hash2 + 1) << 1) + (hash1 >> 5)) ^ comparer.GetHashCode(_data[i]);
  395. if (i == _data.Length - 1) {
  396. break;
  397. }
  398. hash2 = ((hash2 << 5) + ((hash1 - 1) >> 1) + (hash2 >> 27)) ^ comparer.GetHashCode(_data[i + 1]);
  399. }
  400. return hash1 + (hash2 * 1566083941);
  401. }
  402. public override string ToString() {
  403. return __repr__(DefaultContext.Default);
  404. }
  405. #region IValueEquality Members
  406. #if CLR2
  407. int IValueEquality.GetValueHashCode() {
  408. return GetHashCode(DefaultContext.DefaultPythonContext.InitialHasher);
  409. }
  410. bool IValueEquality.ValueEquals(object other) {
  411. if (!Object.ReferenceEquals(other, this)) {
  412. PythonTuple l = other as PythonTuple;
  413. if (l == null || _data.Length != l._data.Length) {
  414. return false;
  415. }
  416. for (int i = 0; i < _data.Length; i++) {
  417. object obj1 = _data[i], obj2 = l._data[i];
  418. if (Object.ReferenceEquals(obj1, obj2)) {
  419. continue;
  420. } else if (!PythonOps.EqualRetBool(obj1, obj2)) {
  421. return false;
  422. }
  423. }
  424. }
  425. return true;
  426. }
  427. #endif
  428. #endregion
  429. #region IStructuralEquatable Members
  430. int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) {
  431. // Optimization for when comparer is IronPython's default IEqualityComparer
  432. PythonContext.PythonEqualityComparer pythonComparer = comparer as PythonContext.PythonEqualityComparer;
  433. if (pythonComparer != null) {
  434. return GetHashCode(pythonComparer.Context.InitialHasher);
  435. }
  436. return GetHashCode(comparer);
  437. }
  438. bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) {
  439. if (!Object.ReferenceEquals(other, this)) {
  440. PythonTuple l = other as PythonTuple;
  441. if (l == null || _data.Length != l._data.Length) {
  442. return false;
  443. }
  444. for (int i = 0; i < _data.Length; i++) {
  445. object obj1 = _data[i], obj2 = l._data[i];
  446. if (Object.ReferenceEquals(obj1, obj2)) {
  447. continue;
  448. } else if (!comparer.Equals(obj1, obj2)) {
  449. return false;
  450. }
  451. }
  452. }
  453. return true;
  454. }
  455. #endregion
  456. #region ICodeFormattable Members
  457. public virtual string/*!*/ __repr__(CodeContext/*!*/ context) {
  458. StringBuilder buf = new StringBuilder();
  459. buf.Append("(");
  460. for (int i = 0; i < _data.Length; i++) {
  461. if (i > 0) buf.Append(", ");
  462. buf.Append(PythonOps.Repr(context, _data[i]));
  463. }
  464. if (_data.Length == 1) buf.Append(",");
  465. buf.Append(")");
  466. return buf.ToString();
  467. }
  468. #endregion
  469. #region IList Members
  470. int IList.Add(object value) {
  471. throw new InvalidOperationException("Tuple is readonly");
  472. }
  473. void IList.Clear() {
  474. throw new InvalidOperationException("Tuple is readonly");
  475. }
  476. void IList.Insert(int index, object value) {
  477. throw new InvalidOperationException("Tuple is readonly");
  478. }
  479. bool IList.IsFixedSize {
  480. get { return true; }
  481. }
  482. bool IList.IsReadOnly {
  483. get { return true; }
  484. }
  485. void IList.Remove(object value) {
  486. throw new InvalidOperationException("Tuple is readonly");
  487. }
  488. void IList.RemoveAt(int index) {
  489. throw new InvalidOperationException("Tuple is readonly");
  490. }
  491. object IList.this[int index] {
  492. get {
  493. return this[index];
  494. }
  495. set {
  496. throw new InvalidOperationException("Tuple is readonly");
  497. }
  498. }
  499. #endregion
  500. }
  501. /// <summary>
  502. /// public class to get optimized
  503. /// </summary>
  504. [PythonType("tupleiterator")]
  505. public sealed class TupleEnumerator : IEnumerable, IEnumerator, IEnumerator<object> {
  506. private int _curIndex;
  507. private PythonTuple _tuple;
  508. public TupleEnumerator(PythonTuple t) {
  509. _tuple = t;
  510. _curIndex = -1;
  511. }
  512. #region IEnumerator Members
  513. public object Current {
  514. get {
  515. // access _data directly because this is what CPython does:
  516. // class T(tuple):
  517. // def __getitem__(self): return None
  518. //
  519. // for x in T((1,2)): print x
  520. // prints 1 and 2
  521. return _tuple._data[_curIndex];
  522. }
  523. }
  524. public bool MoveNext() {
  525. if ((_curIndex + 1) >= _tuple.Count) {
  526. return false;
  527. }
  528. _curIndex++;
  529. return true;
  530. }
  531. public void Reset() {
  532. _curIndex = -1;
  533. }
  534. #endregion
  535. #region IDisposable Members
  536. public void Dispose() {
  537. GC.SuppressFinalize(this);
  538. }
  539. #endregion
  540. #region IEnumerable Members
  541. public IEnumerator GetEnumerator() {
  542. return this;
  543. }
  544. #endregion
  545. }
  546. }