blob: f4016fe9f68a96c90adf823001bdb39a1a3f3af5 [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{
Michael W. Hudsonc9f510a2004-08-02 13:24:54 +000068 PyObject *list, *item, *result;
Raymond Hettinger0c410272004-01-05 10:13:35 +000069 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 {
Michael W. Hudsonc9f510a2004-08-02 13:24:54 +000083 result = PyObject_CallMethod(list, "insert", "iO",
84 index, item);
85 if (result == NULL)
Raymond Hettinger0c410272004-01-05 10:13:35 +000086 return NULL;
Michael W. Hudsonc9f510a2004-08-02 13:24:54 +000087 Py_DECREF(result);
Raymond Hettinger0c410272004-01-05 10:13:35 +000088 }
89
90 Py_RETURN_NONE;
91}
92
93PyDoc_STRVAR(insort_right_doc,
94"insort_right(list, item[, lo[, hi]])\n\
95\n\
96Insert item x in list a, and keep it sorted assuming a is sorted.\n\
97\n\
98If x is already in a, insert it to the right of the rightmost x.\n\
99\n\
100Optional args lo (default 0) and hi (default len(a)) bound the\n\
101slice of a to be searched.\n");
102
103static int
104internal_bisect_left(PyObject *list, PyObject *item, int lo, int hi)
105{
106 PyObject *litem;
107 int mid, res;
108
109 if (hi == -1) {
110 hi = PySequence_Size(list);
111 if (hi < 0)
112 return -1;
113 }
114 while (lo < hi) {
115 mid = (lo + hi) / 2;
116 litem = PySequence_GetItem(list, mid);
117 if (litem == NULL)
118 return -1;
119 res = PyObject_RichCompareBool(litem, item, Py_LT);
120 Py_DECREF(litem);
121 if (res < 0)
122 return -1;
123 if (res)
124 lo = mid + 1;
125 else
126 hi = mid;
127 }
128 return lo;
129}
130
131static PyObject *
132bisect_left(PyObject *self, PyObject *args)
133{
134 PyObject *list, *item;
135 int lo = 0;
136 int hi = -1;
137 int index;
138
139 if (!PyArg_ParseTuple(args, "OO|ii:bisect_left",
140 &list, &item, &lo, &hi))
141 return NULL;
142 index = internal_bisect_left(list, item, lo, hi);
143 if (index < 0)
144 return NULL;
145 return PyInt_FromLong(index);
146}
147
148PyDoc_STRVAR(bisect_left_doc,
149"bisect_left(list, item[, lo[, hi]]) -> index\n\
150\n\
151Return the index where to insert item x in list a, assuming a is sorted.\n\
152\n\
153The return value i is such that all e in a[:i] have e < x, and all e in\n\
154a[i:] have e >= x. So if x already appears in the list, i points just\n\
155before the leftmost x already there.\n\
156\n\
157Optional args lo (default 0) and hi (default len(a)) bound the\n\
158slice of a to be searched.\n");
159
160static PyObject *
161insort_left(PyObject *self, PyObject *args)
162{
Michael W. Hudsonc9f510a2004-08-02 13:24:54 +0000163 PyObject *list, *item, *result;
Raymond Hettinger0c410272004-01-05 10:13:35 +0000164 int lo = 0;
165 int hi = -1;
166 int index;
167
168 if (!PyArg_ParseTuple(args, "OO|ii:insort_left",
169 &list, &item, &lo, &hi))
170 return NULL;
171 index = internal_bisect_left(list, item, lo, hi);
172 if (index < 0)
173 return NULL;
174 if (PyList_Check(list)) {
175 if (PyList_Insert(list, index, item) < 0)
176 return NULL;
177 } else {
Michael W. Hudsonc9f510a2004-08-02 13:24:54 +0000178 result = PyObject_CallMethod(list, "insert", "iO",
179 index, item);
180 if (result == NULL)
Raymond Hettinger0c410272004-01-05 10:13:35 +0000181 return NULL;
Michael W. Hudsonc9f510a2004-08-02 13:24:54 +0000182 Py_DECREF(result);
Raymond Hettinger0c410272004-01-05 10:13:35 +0000183 }
184
185 Py_RETURN_NONE;
186}
187
188PyDoc_STRVAR(insort_left_doc,
189"insort_left(list, item[, lo[, hi]])\n\
190\n\
191Insert item x in list a, and keep it sorted assuming a is sorted.\n\
192\n\
193If x is already in a, insert it to the left of the leftmost x.\n\
194\n\
195Optional args lo (default 0) and hi (default len(a)) bound the\n\
196slice of a to be searched.\n");
197
198PyDoc_STRVAR(bisect_doc, "Alias for bisect_right().\n");
199PyDoc_STRVAR(insort_doc, "Alias for insort_right().\n");
200
201static PyMethodDef bisect_methods[] = {
202 {"bisect_right", (PyCFunction)bisect_right,
203 METH_VARARGS, bisect_right_doc},
204 {"bisect", (PyCFunction)bisect_right,
205 METH_VARARGS, bisect_doc},
206 {"insort_right", (PyCFunction)insort_right,
207 METH_VARARGS, insort_right_doc},
208 {"insort", (PyCFunction)insort_right,
209 METH_VARARGS, insort_doc},
210 {"bisect_left", (PyCFunction)bisect_left,
211 METH_VARARGS, bisect_left_doc},
212 {"insort_left", (PyCFunction)insort_left,
213 METH_VARARGS, insort_left_doc},
214 {NULL, NULL} /* sentinel */
215};
216
217PyDoc_STRVAR(module_doc,
218"Bisection algorithms.\n\
219\n\
220This module provides support for maintaining a list in sorted order without\n\
221having to sort the list after each insertion. For long lists of items with\n\
222expensive comparison operations, this can be an improvement over the more\n\
223common approach.\n");
224
225PyMODINIT_FUNC
226init_bisect(void)
227{
228 PyObject *m;
229
230 m = Py_InitModule3("_bisect", bisect_methods, module_doc);
231}
232