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

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

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