blob: 1280b04af30b9e7174f2dfb89cb44ac51a127960 [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
Martin v. Löwisad0a4622006-02-16 14:30:23 +00009internal_bisect_right(PyObject *list, PyObject *item, Py_ssize_t lo, Py_ssize_t hi)
Raymond Hettinger0c410272004-01-05 10:13:35 +000010{
11 PyObject *litem;
Martin v. Löwisad0a4622006-02-16 14:30:23 +000012 Py_ssize_t mid, res;
Raymond Hettinger0c410272004-01-05 10:13:35 +000013
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 *
Raymond Hettingercc9a9512005-10-05 11:39:12 +000037bisect_right(PyObject *self, PyObject *args, PyObject *kw)
Raymond Hettinger0c410272004-01-05 10:13:35 +000038{
39 PyObject *list, *item;
40 int lo = 0;
41 int hi = -1;
42 int index;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +000043 static char *keywords[] = {"a", "x", "lo", "hi", NULL};
Raymond Hettinger0c410272004-01-05 10:13:35 +000044
Raymond Hettingercc9a9512005-10-05 11:39:12 +000045 if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|ii:bisect_right",
46 keywords, &list, &item, &lo, &hi))
Raymond Hettinger0c410272004-01-05 10:13:35 +000047 return NULL;
48 index = internal_bisect_right(list, item, lo, hi);
49 if (index < 0)
50 return NULL;
Christian Heimes217cfd12007-12-02 14:31:20 +000051 return PyLong_FromLong(index);
Raymond Hettinger0c410272004-01-05 10:13:35 +000052}
53
54PyDoc_STRVAR(bisect_right_doc,
Raymond Hettingercc9a9512005-10-05 11:39:12 +000055"bisect_right(a, x[, lo[, hi]]) -> index\n\
Raymond Hettinger0c410272004-01-05 10:13:35 +000056\n\
57Return the index where to insert item x in list a, assuming a is sorted.\n\
58\n\
59The return value i is such that all e in a[:i] have e <= x, and all e in\n\
60a[i:] have e > x. So if x already appears in the list, i points just\n\
61beyond the rightmost x already there\n\
62\n\
63Optional args lo (default 0) and hi (default len(a)) bound the\n\
64slice of a to be searched.\n");
65
66static PyObject *
Raymond Hettingercc9a9512005-10-05 11:39:12 +000067insort_right(PyObject *self, PyObject *args, PyObject *kw)
Raymond Hettinger0c410272004-01-05 10:13:35 +000068{
Michael W. Hudsonc9f510a2004-08-02 13:24:54 +000069 PyObject *list, *item, *result;
Raymond Hettinger0c410272004-01-05 10:13:35 +000070 int lo = 0;
71 int hi = -1;
72 int index;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +000073 static char *keywords[] = {"a", "x", "lo", "hi", NULL};
Raymond Hettinger0c410272004-01-05 10:13:35 +000074
Raymond Hettingercc9a9512005-10-05 11:39:12 +000075 if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|ii:insort_right",
76 keywords, &list, &item, &lo, &hi))
Raymond Hettinger0c410272004-01-05 10:13:35 +000077 return NULL;
78 index = internal_bisect_right(list, item, lo, hi);
79 if (index < 0)
80 return NULL;
81 if (PyList_Check(list)) {
82 if (PyList_Insert(list, index, item) < 0)
83 return NULL;
84 } else {
Michael W. Hudsonc9f510a2004-08-02 13:24:54 +000085 result = PyObject_CallMethod(list, "insert", "iO",
86 index, item);
87 if (result == NULL)
Raymond Hettinger0c410272004-01-05 10:13:35 +000088 return NULL;
Michael W. Hudsonc9f510a2004-08-02 13:24:54 +000089 Py_DECREF(result);
Raymond Hettinger0c410272004-01-05 10:13:35 +000090 }
91
92 Py_RETURN_NONE;
93}
94
95PyDoc_STRVAR(insort_right_doc,
Raymond Hettingercc9a9512005-10-05 11:39:12 +000096"insort_right(a, x[, lo[, hi]])\n\
Raymond Hettinger0c410272004-01-05 10:13:35 +000097\n\
98Insert item x in list a, and keep it sorted assuming a is sorted.\n\
99\n\
100If x is already in a, insert it to the right of the rightmost x.\n\
101\n\
102Optional args lo (default 0) and hi (default len(a)) bound the\n\
103slice of a to be searched.\n");
104
105static int
106internal_bisect_left(PyObject *list, PyObject *item, int lo, int hi)
107{
108 PyObject *litem;
109 int mid, res;
110
111 if (hi == -1) {
112 hi = PySequence_Size(list);
113 if (hi < 0)
114 return -1;
115 }
116 while (lo < hi) {
117 mid = (lo + hi) / 2;
118 litem = PySequence_GetItem(list, mid);
119 if (litem == NULL)
120 return -1;
121 res = PyObject_RichCompareBool(litem, item, Py_LT);
122 Py_DECREF(litem);
123 if (res < 0)
124 return -1;
125 if (res)
126 lo = mid + 1;
127 else
128 hi = mid;
129 }
130 return lo;
131}
132
133static PyObject *
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000134bisect_left(PyObject *self, PyObject *args, PyObject *kw)
Raymond Hettinger0c410272004-01-05 10:13:35 +0000135{
136 PyObject *list, *item;
137 int lo = 0;
138 int hi = -1;
139 int index;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +0000140 static char *keywords[] = {"a", "x", "lo", "hi", NULL};
Raymond Hettinger0c410272004-01-05 10:13:35 +0000141
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000142 if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|ii:bisect_left",
143 keywords, &list, &item, &lo, &hi))
Raymond Hettinger0c410272004-01-05 10:13:35 +0000144 return NULL;
145 index = internal_bisect_left(list, item, lo, hi);
146 if (index < 0)
147 return NULL;
Christian Heimes217cfd12007-12-02 14:31:20 +0000148 return PyLong_FromLong(index);
Raymond Hettinger0c410272004-01-05 10:13:35 +0000149}
150
151PyDoc_STRVAR(bisect_left_doc,
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000152"bisect_left(a, x[, lo[, hi]]) -> index\n\
Raymond Hettinger0c410272004-01-05 10:13:35 +0000153\n\
154Return the index where to insert item x in list a, assuming a is sorted.\n\
155\n\
156The return value i is such that all e in a[:i] have e < x, and all e in\n\
157a[i:] have e >= x. So if x already appears in the list, i points just\n\
158before the leftmost x already there.\n\
159\n\
160Optional args lo (default 0) and hi (default len(a)) bound the\n\
161slice of a to be searched.\n");
162
163static PyObject *
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000164insort_left(PyObject *self, PyObject *args, PyObject *kw)
Raymond Hettinger0c410272004-01-05 10:13:35 +0000165{
Michael W. Hudsonc9f510a2004-08-02 13:24:54 +0000166 PyObject *list, *item, *result;
Raymond Hettinger0c410272004-01-05 10:13:35 +0000167 int lo = 0;
168 int hi = -1;
169 int index;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +0000170 static char *keywords[] = {"a", "x", "lo", "hi", NULL};
Raymond Hettinger0c410272004-01-05 10:13:35 +0000171
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000172 if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|ii:insort_left",
173 keywords, &list, &item, &lo, &hi))
Raymond Hettinger0c410272004-01-05 10:13:35 +0000174 return NULL;
175 index = internal_bisect_left(list, item, lo, hi);
176 if (index < 0)
177 return NULL;
178 if (PyList_Check(list)) {
179 if (PyList_Insert(list, index, item) < 0)
180 return NULL;
181 } else {
Michael W. Hudsonc9f510a2004-08-02 13:24:54 +0000182 result = PyObject_CallMethod(list, "insert", "iO",
183 index, item);
184 if (result == NULL)
Raymond Hettinger0c410272004-01-05 10:13:35 +0000185 return NULL;
Michael W. Hudsonc9f510a2004-08-02 13:24:54 +0000186 Py_DECREF(result);
Raymond Hettinger0c410272004-01-05 10:13:35 +0000187 }
188
189 Py_RETURN_NONE;
190}
191
192PyDoc_STRVAR(insort_left_doc,
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000193"insort_left(a, x[, lo[, hi]])\n\
Raymond Hettinger0c410272004-01-05 10:13:35 +0000194\n\
195Insert item x in list a, and keep it sorted assuming a is sorted.\n\
196\n\
197If x is already in a, insert it to the left of the leftmost x.\n\
198\n\
199Optional args lo (default 0) and hi (default len(a)) bound the\n\
200slice of a to be searched.\n");
201
202PyDoc_STRVAR(bisect_doc, "Alias for bisect_right().\n");
203PyDoc_STRVAR(insort_doc, "Alias for insort_right().\n");
204
205static PyMethodDef bisect_methods[] = {
206 {"bisect_right", (PyCFunction)bisect_right,
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000207 METH_VARARGS|METH_KEYWORDS, bisect_right_doc},
Raymond Hettinger0c410272004-01-05 10:13:35 +0000208 {"bisect", (PyCFunction)bisect_right,
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000209 METH_VARARGS|METH_KEYWORDS, bisect_doc},
Raymond Hettinger0c410272004-01-05 10:13:35 +0000210 {"insort_right", (PyCFunction)insort_right,
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000211 METH_VARARGS|METH_KEYWORDS, insort_right_doc},
Raymond Hettinger0c410272004-01-05 10:13:35 +0000212 {"insort", (PyCFunction)insort_right,
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000213 METH_VARARGS|METH_KEYWORDS, insort_doc},
Raymond Hettinger0c410272004-01-05 10:13:35 +0000214 {"bisect_left", (PyCFunction)bisect_left,
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000215 METH_VARARGS|METH_KEYWORDS, bisect_left_doc},
Raymond Hettinger0c410272004-01-05 10:13:35 +0000216 {"insort_left", (PyCFunction)insort_left,
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000217 METH_VARARGS|METH_KEYWORDS, insort_left_doc},
Raymond Hettinger0c410272004-01-05 10:13:35 +0000218 {NULL, NULL} /* sentinel */
219};
220
221PyDoc_STRVAR(module_doc,
222"Bisection algorithms.\n\
223\n\
224This module provides support for maintaining a list in sorted order without\n\
225having to sort the list after each insertion. For long lists of items with\n\
226expensive comparison operations, this can be an improvement over the more\n\
227common approach.\n");
228
Raymond Hettinger0c410272004-01-05 10:13:35 +0000229
Martin v. Löwis1a214512008-06-11 05:26:20 +0000230static struct PyModuleDef _bisectmodule = {
231 PyModuleDef_HEAD_INIT,
232 "_bisect",
233 module_doc,
234 -1,
235 bisect_methods,
236 NULL,
237 NULL,
238 NULL,
239 NULL
240};
241
242PyMODINIT_FUNC
243PyInit__bisect(void)
244{
245 return PyModule_Create(&_bisectmodule);
Raymond Hettinger0c410272004-01-05 10:13:35 +0000246}