blob: d3361586488e809674f588593f641dc1a5f36a89 [file] [log] [blame]
Raymond Hettinger0c410272004-01-05 10:13:35 +00001/* Bisection algorithms. Drop in replacement for bisect.py
2
3Converted to C by Dmitry Vasiliev (dima at hlabs.spb.ru).
4*/
5
6#include "Python.h"
7
8static int
9internal_bisect_right(PyObject *list, PyObject *item, int lo, int hi)
10{
11 PyObject *litem;
12 int mid, res;
13
14 if (hi == -1) {
15 hi = PySequence_Size(list);
16 if (hi < 0)
17 return -1;
18 }
19 while (lo < hi) {
20 mid = (lo + hi) / 2;
21 litem = PySequence_GetItem(list, mid);
22 if (litem == NULL)
23 return -1;
24 res = PyObject_RichCompareBool(item, litem, Py_LT);
25 Py_DECREF(litem);
26 if (res < 0)
27 return -1;
28 if (res)
29 hi = mid;
30 else
31 lo = mid + 1;
32 }
33 return lo;
34}
35
36static PyObject *
37bisect_right(PyObject *self, PyObject *args)
38{
39 PyObject *list, *item;
40 int lo = 0;
41 int hi = -1;
42 int index;
43
44 if (!PyArg_ParseTuple(args, "OO|ii:bisect_right",
45 &list, &item, &lo, &hi))
46 return NULL;
47 index = internal_bisect_right(list, item, lo, hi);
48 if (index < 0)
49 return NULL;
50 return PyInt_FromLong(index);
51}
52
53PyDoc_STRVAR(bisect_right_doc,
54"bisect_right(list, item[, lo[, hi]]) -> index\n\
55\n\
56Return the index where to insert item x in list a, assuming a is sorted.\n\
57\n\
58The return value i is such that all e in a[:i] have e <= x, and all e in\n\
59a[i:] have e > x. So if x already appears in the list, i points just\n\
60beyond the rightmost x already there\n\
61\n\
62Optional args lo (default 0) and hi (default len(a)) bound the\n\
63slice of a to be searched.\n");
64
65static PyObject *
66insort_right(PyObject *self, PyObject *args)
67{
68 PyObject *list, *item;
69 int lo = 0;
70 int hi = -1;
71 int index;
72
73 if (!PyArg_ParseTuple(args, "OO|ii:insort_right",
74 &list, &item, &lo, &hi))
75 return NULL;
76 index = internal_bisect_right(list, item, lo, hi);
77 if (index < 0)
78 return NULL;
79 if (PyList_Check(list)) {
80 if (PyList_Insert(list, index, item) < 0)
81 return NULL;
82 } else {
83 if (PyObject_CallMethod(list, "insert", "iO", index, item)
84 == NULL)
85 return NULL;
86 }
87
88 Py_RETURN_NONE;
89}
90
91PyDoc_STRVAR(insort_right_doc,
92"insort_right(list, item[, lo[, hi]])\n\
93\n\
94Insert item x in list a, and keep it sorted assuming a is sorted.\n\
95\n\
96If x is already in a, insert it to the right of the rightmost x.\n\
97\n\
98Optional args lo (default 0) and hi (default len(a)) bound the\n\
99slice of a to be searched.\n");
100
101static int
102internal_bisect_left(PyObject *list, PyObject *item, int lo, int hi)
103{
104 PyObject *litem;
105 int mid, res;
106
107 if (hi == -1) {
108 hi = PySequence_Size(list);
109 if (hi < 0)
110 return -1;
111 }
112 while (lo < hi) {
113 mid = (lo + hi) / 2;
114 litem = PySequence_GetItem(list, mid);
115 if (litem == NULL)
116 return -1;
117 res = PyObject_RichCompareBool(litem, item, Py_LT);
118 Py_DECREF(litem);
119 if (res < 0)
120 return -1;
121 if (res)
122 lo = mid + 1;
123 else
124 hi = mid;
125 }
126 return lo;
127}
128
129static PyObject *
130bisect_left(PyObject *self, PyObject *args)
131{
132 PyObject *list, *item;
133 int lo = 0;
134 int hi = -1;
135 int index;
136
137 if (!PyArg_ParseTuple(args, "OO|ii:bisect_left",
138 &list, &item, &lo, &hi))
139 return NULL;
140 index = internal_bisect_left(list, item, lo, hi);
141 if (index < 0)
142 return NULL;
143 return PyInt_FromLong(index);
144}
145
146PyDoc_STRVAR(bisect_left_doc,
147"bisect_left(list, item[, lo[, hi]]) -> index\n\
148\n\
149Return the index where to insert item x in list a, assuming a is sorted.\n\
150\n\
151The return value i is such that all e in a[:i] have e < x, and all e in\n\
152a[i:] have e >= x. So if x already appears in the list, i points just\n\
153before the leftmost x already there.\n\
154\n\
155Optional args lo (default 0) and hi (default len(a)) bound the\n\
156slice of a to be searched.\n");
157
158static PyObject *
159insort_left(PyObject *self, PyObject *args)
160{
161 PyObject *list, *item;
162 int lo = 0;
163 int hi = -1;
164 int index;
165
166 if (!PyArg_ParseTuple(args, "OO|ii:insort_left",
167 &list, &item, &lo, &hi))
168 return NULL;
169 index = internal_bisect_left(list, item, lo, hi);
170 if (index < 0)
171 return NULL;
172 if (PyList_Check(list)) {
173 if (PyList_Insert(list, index, item) < 0)
174 return NULL;
175 } else {
176 if (PyObject_CallMethod(list, "insert", "iO", index, item)
177 == NULL)
178 return NULL;
179 }
180
181 Py_RETURN_NONE;
182}
183
184PyDoc_STRVAR(insort_left_doc,
185"insort_left(list, item[, lo[, hi]])\n\
186\n\
187Insert item x in list a, and keep it sorted assuming a is sorted.\n\
188\n\
189If x is already in a, insert it to the left of the leftmost x.\n\
190\n\
191Optional args lo (default 0) and hi (default len(a)) bound the\n\
192slice of a to be searched.\n");
193
194PyDoc_STRVAR(bisect_doc, "Alias for bisect_right().\n");
195PyDoc_STRVAR(insort_doc, "Alias for insort_right().\n");
196
197static PyMethodDef bisect_methods[] = {
198 {"bisect_right", (PyCFunction)bisect_right,
199 METH_VARARGS, bisect_right_doc},
200 {"bisect", (PyCFunction)bisect_right,
201 METH_VARARGS, bisect_doc},
202 {"insort_right", (PyCFunction)insort_right,
203 METH_VARARGS, insort_right_doc},
204 {"insort", (PyCFunction)insort_right,
205 METH_VARARGS, insort_doc},
206 {"bisect_left", (PyCFunction)bisect_left,
207 METH_VARARGS, bisect_left_doc},
208 {"insort_left", (PyCFunction)insort_left,
209 METH_VARARGS, insort_left_doc},
210 {NULL, NULL} /* sentinel */
211};
212
213PyDoc_STRVAR(module_doc,
214"Bisection algorithms.\n\
215\n\
216This module provides support for maintaining a list in sorted order without\n\
217having to sort the list after each insertion. For long lists of items with\n\
218expensive comparison operations, this can be an improvement over the more\n\
219common approach.\n");
220
221PyMODINIT_FUNC
222init_bisect(void)
223{
224 PyObject *m;
225
226 m = Py_InitModule3("_bisect", bisect_methods, module_doc);
227}
228