PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/DICK.B1/IronPython/Runtime/Slice.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 210 lines | 137 code | 46 blank | 27 comment | 21 complexity | 7a97ed248ef31b9364c69c678f61eba1 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 Microsoft.Scripting;
  18. using Microsoft.Scripting.Runtime;
  19. using IronPython.Runtime.Operations;
  20. using IronPython.Runtime.Types;
  21. namespace IronPython.Runtime {
  22. [PythonType("slice")]
  23. public sealed class Slice : ICodeFormattable, IComparable, ISlice {
  24. private readonly object _start, _stop, _step;
  25. public Slice(object stop) : this(null, stop, null) { }
  26. public Slice(object start, object stop) : this(start, stop, null) { }
  27. public Slice(object start, object stop, object step) {
  28. _start = start;
  29. _stop = stop;
  30. _step = step;
  31. }
  32. #region Python Public API Surface
  33. public object start {
  34. get { return _start; }
  35. }
  36. public object stop {
  37. get { return _stop; }
  38. }
  39. public object step {
  40. get { return _step; }
  41. }
  42. public int __cmp__(Slice obj) {
  43. return PythonOps.CompareArrays(new object[] { _start, _stop, _step }, 3,
  44. new object[] { obj._start, obj._stop, obj._step }, 3);
  45. }
  46. public void indices(int len, out int ostart, out int ostop, out int ostep) {
  47. int count;
  48. PythonOps.FixSlice(len, _start, _stop, _step, out ostart, out ostop, out ostep, out count);
  49. }
  50. public void indices(object len, out int ostart, out int ostop, out int ostep) {
  51. int count;
  52. PythonOps.FixSlice(Converter.ConvertToIndex(len), _start, _stop, _step, out ostart, out ostop, out ostep, out count);
  53. }
  54. public PythonTuple __reduce__() {
  55. return PythonTuple.MakeTuple(
  56. DynamicHelpers.GetPythonTypeFromType(typeof(Slice)),
  57. PythonTuple.MakeTuple(
  58. _start,
  59. _stop,
  60. _step
  61. )
  62. );
  63. }
  64. #endregion
  65. #region IComparable Members
  66. int IComparable.CompareTo(object obj) {
  67. Slice other = obj as Slice;
  68. if (other == null) throw new ArgumentException("expected slice");
  69. return __cmp__(other);
  70. }
  71. #endregion
  72. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
  73. public int __hash__() {
  74. throw PythonOps.TypeErrorForUnhashableType("slice");
  75. }
  76. #region ISlice Members
  77. object ISlice.Start {
  78. get { return start; }
  79. }
  80. object ISlice.Stop {
  81. get { return stop; }
  82. }
  83. object ISlice.Step {
  84. get { return step; }
  85. }
  86. #endregion
  87. #region ICodeFormattable Members
  88. public string/*!*/ __repr__(CodeContext/*!*/ context) {
  89. return string.Format("slice({0}, {1}, {2})", PythonOps.Repr(context, _start), PythonOps.Repr(context, _stop), PythonOps.Repr(context, _step));
  90. }
  91. #endregion
  92. #region Internal Implementation details
  93. internal static void FixSliceArguments(int size, ref int start, ref int stop) {
  94. start = start < 0 ? 0 : start > size ? size : start;
  95. stop = stop < 0 ? 0 : stop > size ? size : stop;
  96. }
  97. /// <summary>
  98. /// Gets the indices for the deprecated __getslice__, __setslice__, __delslice__ functions
  99. ///
  100. /// This form is deprecated in favor of using __getitem__ w/ a slice object as an index. This
  101. /// form also has subtly different mechanisms for fixing the slice index before calling the function.
  102. ///
  103. /// If an index is negative and __len__ is not defined on the object than an AttributeError
  104. /// is raised.
  105. /// </summary>
  106. internal void DeprecatedFixed(object self, out int newStart, out int newStop) {
  107. bool calcedLength = false; // only call __len__ once, even if we need it twice
  108. int length = 0;
  109. if (_start != null) {
  110. newStart = Converter.ConvertToIndex(_start);
  111. if (newStart < 0) {
  112. calcedLength = true;
  113. length = PythonOps.Length(self);
  114. newStart += length;
  115. }
  116. } else {
  117. newStart = 0;
  118. }
  119. if (_stop != null) {
  120. newStop = Converter.ConvertToIndex(_stop);
  121. if (newStop < 0) {
  122. if (!calcedLength) length = PythonOps.Length(self);
  123. newStop += length;
  124. }
  125. } else {
  126. newStop = Int32.MaxValue;
  127. }
  128. }
  129. internal delegate void SliceAssign(int index, object value);
  130. internal void DoSliceAssign(SliceAssign assign, int size, object value) {
  131. int ostart, ostop, ostep;
  132. indices(size, out ostart, out ostop, out ostep);
  133. if (this._step == null) throw PythonOps.ValueError("cannot do slice assignment w/ no step");
  134. DoSliceAssign(assign, ostart, ostop, ostep, value);
  135. }
  136. private static void DoSliceAssign(SliceAssign assign, int start, int stop, int step, object value) {
  137. stop = step > 0 ? Math.Max(stop, start) : Math.Min(stop, start);
  138. int n = Math.Max(0, (step > 0 ? (stop - start + step - 1) : (stop - start + step + 1)) / step);
  139. // fast paths, if we know the size then we can
  140. // do this quickly.
  141. if (value is IList) {
  142. ListSliceAssign(assign, start, n, step, value as IList);
  143. } else {
  144. OtherSliceAssign(assign, start, stop, step, value);
  145. }
  146. }
  147. private static void ListSliceAssign(SliceAssign assign, int start, int n, int step, IList lst) {
  148. if (lst.Count < n) throw PythonOps.ValueError("too few items in the enumerator. need {0} have {1}", n, lst.Count);
  149. else if (lst.Count != n) throw PythonOps.ValueError("too many items in the enumerator need {0} have {1}", n, lst.Count);
  150. for (int i = 0, index = start; i < n; i++, index += step) {
  151. assign(index, lst[i]);
  152. }
  153. }
  154. private static void OtherSliceAssign(SliceAssign assign, int start, int stop, int step, object value) {
  155. // get enumerable data into a list, and then
  156. // do the slice.
  157. IEnumerator enumerator = PythonOps.GetEnumerator(value);
  158. List sliceData = new List();
  159. while (enumerator.MoveNext()) sliceData.AddNoLock(enumerator.Current);
  160. DoSliceAssign(assign, start, stop, step, sliceData);
  161. }
  162. #endregion
  163. }
  164. }