PageRenderTime 48ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/Languages/IronPython/IronPython.Modules/_bisect.cs

http://github.com/IronLanguages/main
C# | 236 lines | 200 code | 32 blank | 4 comment | 38 complexity | 4deaf149d1d7d61b6c325f590235da1f MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Runtime.CompilerServices;
  5. using System.Runtime.InteropServices;
  6. using IronPython.Runtime;
  7. using IronPython.Runtime.Binding;
  8. using IronPython.Runtime.Exceptions;
  9. using IronPython.Runtime.Operations;
  10. using IronPython.Runtime.Types;
  11. using Microsoft.Scripting;
  12. using Microsoft.Scripting.Generation;
  13. using Microsoft.Scripting.Runtime;
  14. using Microsoft.Scripting.Utils;
  15. [assembly: PythonModule("_bisect", typeof(IronPython.Modules.PythonBisectModule))]
  16. namespace IronPython.Modules {
  17. public class PythonBisectModule {
  18. public const string __doc__ = @"Bisection algorithms.
  19. This module provides support for maintaining a list in sorted order without
  20. having to sort the list after each insertion. For long lists of items with
  21. expensive comparison operations, this can be an improvement over the more
  22. common approach.
  23. ";
  24. #region Private Implementation Details
  25. private static int InternalBisectLeft(CodeContext/*!*/ context, List list, object item, int lo, int hi) {
  26. int mid;
  27. object litem;
  28. if (lo < 0) {
  29. throw PythonOps.ValueError("lo must be non-negative");
  30. }
  31. if (hi == -1) {
  32. hi = list.Count;
  33. }
  34. IComparer comparer = PythonContext.GetContext(context).GetComparer(null, GetComparisonType(list));
  35. while (lo < hi) {
  36. mid = (int)(((long)lo + hi) / 2);
  37. litem = list[mid];
  38. if (comparer.Compare(litem, item) < 0)
  39. lo = mid + 1;
  40. else
  41. hi = mid;
  42. }
  43. return lo;
  44. }
  45. private static int InternalBisectLeft(CodeContext/*!*/ context, object list, object item, int lo, int hi) {
  46. int mid;
  47. object litem;
  48. if (lo < 0) {
  49. throw PythonOps.ValueError("lo must be non-negative");
  50. }
  51. if (hi == -1) {
  52. hi = PythonOps.Length(list);
  53. }
  54. IComparer comparer = PythonContext.GetContext(context).GetComparer(null, GetComparisonType(context, list));
  55. while (lo < hi) {
  56. mid = (int)(((long)lo + hi) / 2);
  57. litem = PythonOps.GetIndex(context, list, mid);
  58. if (comparer.Compare(litem, item) < 0)
  59. lo = mid + 1;
  60. else
  61. hi = mid;
  62. }
  63. return lo;
  64. }
  65. private static int InternalBisectRight(CodeContext/*!*/ context, List list, object item, int lo, int hi) {
  66. object litem;
  67. int mid;
  68. if (lo < 0) {
  69. throw PythonOps.ValueError("lo must be non-negative");
  70. }
  71. if (hi == -1) {
  72. hi = list.Count;
  73. }
  74. IComparer comparer = PythonContext.GetContext(context).GetComparer(null, GetComparisonType(list));
  75. while (lo < hi) {
  76. mid = (int)(((long)lo + hi) / 2);
  77. litem = list[mid];
  78. if (comparer.Compare(item, litem) < 0)
  79. hi = mid;
  80. else
  81. lo = mid + 1;
  82. }
  83. return lo;
  84. }
  85. private static int InternalBisectRight(CodeContext/*!*/ context, object list, object item, int lo, int hi) {
  86. object litem;
  87. int mid;
  88. if (lo < 0) {
  89. throw PythonOps.ValueError("lo must be non-negative");
  90. }
  91. if (hi == -1) {
  92. hi = PythonOps.Length(list);
  93. }
  94. IComparer comparer = PythonContext.GetContext(context).GetComparer(null, GetComparisonType(context, list));
  95. while (lo < hi) {
  96. mid = (int)(((long)lo + hi) / 2);
  97. litem = PythonOps.GetIndex(context, list, mid);
  98. if (comparer.Compare(item, litem) < 0)
  99. hi = mid;
  100. else
  101. lo = mid + 1;
  102. }
  103. return lo;
  104. }
  105. private static Type GetComparisonType(CodeContext/*!*/ context, object a) {
  106. if (PythonOps.Length(a) > 0) {
  107. // use the 1st index to determine the type - we're assuming lists are
  108. // homogeneous
  109. return CompilerHelpers.GetType(PythonOps.GetIndex(context, a, 0));
  110. }
  111. return typeof(object);
  112. }
  113. private static Type GetComparisonType(List a) {
  114. if (a.Count > 0) {
  115. // use the 1st index to determine the type - we're assuming lists are
  116. // homogeneous
  117. return CompilerHelpers.GetType(a[0]);
  118. }
  119. return typeof(object);
  120. }
  121. #endregion Private Implementation Details
  122. #region Public API Surface
  123. [Documentation(@"bisect_right(a, x[, lo[, hi]]) -> index
  124. Return the index where to insert item x in list a, assuming a is sorted.
  125. The return value i is such that all e in a[:i] have e <= x, and all e in
  126. a[i:] have e > x. So if x already appears in the list, i points just
  127. beyond the rightmost x already there
  128. Optional args lo (default 0) and hi (default len(a)) bound the
  129. slice of a to be searched.
  130. ")]
  131. public static object bisect_right(CodeContext/*!*/ context, object a, object x, [DefaultParameterValue(0)] int lo, [DefaultParameterValue(-1)] int hi) {
  132. List l = a as List;
  133. if (l != null && l.GetType() == typeof(List)) {
  134. return InternalBisectRight(context, l, x, lo, hi);
  135. }
  136. return InternalBisectRight(context, a, x, lo, hi);
  137. }
  138. [Documentation(@"insort_right(a, x[, lo[, hi]])
  139. Insert item x in list a, and keep it sorted assuming a is sorted.
  140. If x is already in a, insert it to the right of the rightmost x.
  141. Optional args lo (default 0) and hi (default len(a)) bound the
  142. slice of a to be searched.
  143. ")]
  144. public static void insort_right(CodeContext/*!*/ context, object a, object x, [DefaultParameterValue(0)] int lo, [DefaultParameterValue(-1)] int hi) {
  145. List l = a as List;
  146. if (l != null && l.GetType() == typeof(List)) {
  147. l.Insert(InternalBisectRight(context, l, x, lo, hi), x);
  148. return;
  149. }
  150. PythonOps.Invoke(context, a, "insert", InternalBisectRight(context, a, x, lo, hi), x);
  151. }
  152. [Documentation(@"bisect_left(a, x[, lo[, hi]]) -> index
  153. Return the index where to insert item x in list a, assuming a is sorted.
  154. The return value i is such that all e in a[:i] have e < x, and all e in
  155. a[i:] have e >= x. So if x already appears in the list, i points just
  156. before the leftmost x already there.
  157. Optional args lo (default 0) and hi (default len(a)) bound the
  158. slice of a to be searched.
  159. ")]
  160. public static object bisect_left(CodeContext/*!*/ context, object a, object x, [DefaultParameterValue(0)] int lo, [DefaultParameterValue(-1)] int hi) {
  161. List l = a as List;
  162. if (l != null && l.GetType() == typeof(List)) {
  163. return InternalBisectLeft(context, l, x, lo, hi);
  164. }
  165. return InternalBisectLeft(context, a, x, lo, hi);
  166. }
  167. [Documentation(@"insort_left(a, x[, lo[, hi]])
  168. Insert item x in list a, and keep it sorted assuming a is sorted.
  169. If x is already in a, insert it to the left of the leftmost x.
  170. Optional args lo (default 0) and hi (default len(a)) bound the
  171. slice of a to be searched.
  172. ")]
  173. public static void insort_left(CodeContext/*!*/ context, object a, object x, [DefaultParameterValue(0)] int lo, [DefaultParameterValue(-1)] int hi) {
  174. List l = a as List;
  175. if (l != null && l.GetType() == typeof(List)) {
  176. l.Insert(InternalBisectLeft(context, l, x, lo, hi), x);
  177. return;
  178. }
  179. PythonOps.Invoke(context, a, "insert", InternalBisectLeft(context, a, x, lo, hi), x);
  180. }
  181. [Documentation("Alias for bisect_right().")]
  182. public static object bisect(CodeContext/*!*/ context, object a, object x, [DefaultParameterValue(0)] int lo, [DefaultParameterValue(-1)] int hi) {
  183. return bisect_right(context, a, x, lo, hi);
  184. }
  185. [Documentation("Alias for insort_right().")]
  186. public static void insort(CodeContext/*!*/ context, object a, object x, [DefaultParameterValue(0)] int lo, [DefaultParameterValue(-1)] int hi) {
  187. insort_right(context, a, x, lo, hi);
  188. }
  189. #endregion Public API Surface
  190. }
  191. }