PageRenderTime 40ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/Languages/IronPython/IronPython/Runtime/PythonTuple.cs

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