blob: 7fecfc6937b808476a8ec2b94003bf74fc351b03 [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
Benjamin Petersond6313712008-07-31 16:23:04 +00008static Py_ssize_t
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{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000011 PyObject *litem;
12 Py_ssize_t mid, res;
Raymond Hettinger0c410272004-01-05 10:13:35 +000013
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000014 if (lo < 0) {
15 PyErr_SetString(PyExc_ValueError, "lo must be non-negative");
16 return -1;
17 }
18 if (hi == -1) {
19 hi = PySequence_Size(list);
20 if (hi < 0)
21 return -1;
22 }
23 while (lo < hi) {
24 mid = (lo + hi) / 2;
25 litem = PySequence_GetItem(list, mid);
26 if (litem == NULL)
27 return -1;
28 res = PyObject_RichCompareBool(item, litem, Py_LT);
29 Py_DECREF(litem);
30 if (res < 0)
31 return -1;
32 if (res)
33 hi = mid;
34 else
35 lo = mid + 1;
36 }
37 return lo;
Raymond Hettinger0c410272004-01-05 10:13:35 +000038}
39
40static PyObject *
Raymond Hettingercc9a9512005-10-05 11:39:12 +000041bisect_right(PyObject *self, PyObject *args, PyObject *kw)
Raymond Hettinger0c410272004-01-05 10:13:35 +000042{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000043 PyObject *list, *item;
44 Py_ssize_t lo = 0;
45 Py_ssize_t hi = -1;
46 Py_ssize_t index;
47 static char *keywords[] = {"a", "x", "lo", "hi", NULL};
Raymond Hettinger0c410272004-01-05 10:13:35 +000048
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000049 if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|nn:bisect_right",
50 keywords, &list, &item, &lo, &hi))
51 return NULL;
52 index = internal_bisect_right(list, item, lo, hi);
53 if (index < 0)
54 return NULL;
55 return PyLong_FromSsize_t(index);
Raymond Hettinger0c410272004-01-05 10:13:35 +000056}
57
58PyDoc_STRVAR(bisect_right_doc,
Raymond Hettingercc9a9512005-10-05 11:39:12 +000059"bisect_right(a, x[, lo[, hi]]) -> index\n\
Raymond Hettinger0c410272004-01-05 10:13:35 +000060\n\
61Return the index where to insert item x in list a, assuming a is sorted.\n\
62\n\
63The return value i is such that all e in a[:i] have e <= x, and all e in\n\
64a[i:] have e > x. So if x already appears in the list, i points just\n\
65beyond the rightmost x already there\n\
66\n\
67Optional args lo (default 0) and hi (default len(a)) bound the\n\
68slice of a to be searched.\n");
69
70static PyObject *
Raymond Hettingercc9a9512005-10-05 11:39:12 +000071insort_right(PyObject *self, PyObject *args, PyObject *kw)
Raymond Hettinger0c410272004-01-05 10:13:35 +000072{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000073 PyObject *list, *item, *result;
74 Py_ssize_t lo = 0;
75 Py_ssize_t hi = -1;
76 Py_ssize_t index;
77 static char *keywords[] = {"a", "x", "lo", "hi", NULL};
Raymond Hettinger0c410272004-01-05 10:13:35 +000078
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000079 if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|nn:insort_right",
80 keywords, &list, &item, &lo, &hi))
81 return NULL;
82 index = internal_bisect_right(list, item, lo, hi);
83 if (index < 0)
84 return NULL;
85 if (PyList_CheckExact(list)) {
86 if (PyList_Insert(list, index, item) < 0)
87 return NULL;
88 } else {
Raymond Hettinger6b3d72c2010-09-01 08:56:10 +000089 result = PyObject_CallMethod(list, "insert", "nO", index, item);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000090 if (result == NULL)
91 return NULL;
92 Py_DECREF(result);
93 }
Raymond Hettinger0c410272004-01-05 10:13:35 +000094
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000095 Py_RETURN_NONE;
Raymond Hettinger0c410272004-01-05 10:13:35 +000096}
97
98PyDoc_STRVAR(insort_right_doc,
Raymond Hettingercc9a9512005-10-05 11:39:12 +000099"insort_right(a, x[, lo[, hi]])\n\
Raymond Hettinger0c410272004-01-05 10:13:35 +0000100\n\
101Insert item x in list a, and keep it sorted assuming a is sorted.\n\
102\n\
103If x is already in a, insert it to the right of the rightmost x.\n\
104\n\
105Optional args lo (default 0) and hi (default len(a)) bound the\n\
106slice of a to be searched.\n");
107
Benjamin Petersond6313712008-07-31 16:23:04 +0000108static Py_ssize_t
109internal_bisect_left(PyObject *list, PyObject *item, Py_ssize_t lo, Py_ssize_t hi)
Raymond Hettinger0c410272004-01-05 10:13:35 +0000110{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000111 PyObject *litem;
112 Py_ssize_t mid, res;
Raymond Hettinger0c410272004-01-05 10:13:35 +0000113
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000114 if (lo < 0) {
115 PyErr_SetString(PyExc_ValueError, "lo must be non-negative");
116 return -1;
117 }
118 if (hi == -1) {
119 hi = PySequence_Size(list);
120 if (hi < 0)
121 return -1;
122 }
123 while (lo < hi) {
124 mid = (lo + hi) / 2;
125 litem = PySequence_GetItem(list, mid);
126 if (litem == NULL)
127 return -1;
128 res = PyObject_RichCompareBool(litem, item, Py_LT);
129 Py_DECREF(litem);
130 if (res < 0)
131 return -1;
132 if (res)
133 lo = mid + 1;
134 else
135 hi = mid;
136 }
137 return lo;
Raymond Hettinger0c410272004-01-05 10:13:35 +0000138}
139
140static PyObject *
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000141bisect_left(PyObject *self, PyObject *args, PyObject *kw)
Raymond Hettinger0c410272004-01-05 10:13:35 +0000142{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000143 PyObject *list, *item;
144 Py_ssize_t lo = 0;
145 Py_ssize_t hi = -1;
146 Py_ssize_t index;
147 static char *keywords[] = {"a", "x", "lo", "hi", NULL};
Raymond Hettinger0c410272004-01-05 10:13:35 +0000148
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000149 if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|nn:bisect_left",
150 keywords, &list, &item, &lo, &hi))
151 return NULL;
152 index = internal_bisect_left(list, item, lo, hi);
153 if (index < 0)
154 return NULL;
155 return PyLong_FromSsize_t(index);
Raymond Hettinger0c410272004-01-05 10:13:35 +0000156}
157
158PyDoc_STRVAR(bisect_left_doc,
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000159"bisect_left(a, x[, lo[, hi]]) -> index\n\
Raymond Hettinger0c410272004-01-05 10:13:35 +0000160\n\
161Return the index where to insert item x in list a, assuming a is sorted.\n\
162\n\
163The return value i is such that all e in a[:i] have e < x, and all e in\n\
164a[i:] have e >= x. So if x already appears in the list, i points just\n\
165before the leftmost x already there.\n\
166\n\
167Optional args lo (default 0) and hi (default len(a)) bound the\n\
168slice of a to be searched.\n");
169
170static PyObject *
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000171insort_left(PyObject *self, PyObject *args, PyObject *kw)
Raymond Hettinger0c410272004-01-05 10:13:35 +0000172{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000173 PyObject *list, *item, *result;
174 Py_ssize_t lo = 0;
175 Py_ssize_t hi = -1;
176 Py_ssize_t index;
177 static char *keywords[] = {"a", "x", "lo", "hi", NULL};
Raymond Hettinger0c410272004-01-05 10:13:35 +0000178
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000179 if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|nn:insort_left",
180 keywords, &list, &item, &lo, &hi))
181 return NULL;
182 index = internal_bisect_left(list, item, lo, hi);
183 if (index < 0)
184 return NULL;
185 if (PyList_CheckExact(list)) {
186 if (PyList_Insert(list, index, item) < 0)
187 return NULL;
188 } else {
Raymond Hettinger6b3d72c2010-09-01 08:56:10 +0000189 result = PyObject_CallMethod(list, "insert", "iO", index, item);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000190 if (result == NULL)
191 return NULL;
192 Py_DECREF(result);
193 }
Raymond Hettinger0c410272004-01-05 10:13:35 +0000194
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000195 Py_RETURN_NONE;
Raymond Hettinger0c410272004-01-05 10:13:35 +0000196}
197
198PyDoc_STRVAR(insort_left_doc,
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000199"insort_left(a, x[, lo[, hi]])\n\
Raymond Hettinger0c410272004-01-05 10:13:35 +0000200\n\
201Insert item x in list a, and keep it sorted assuming a is sorted.\n\
202\n\
203If x is already in a, insert it to the left of the leftmost x.\n\
204\n\
205Optional args lo (default 0) and hi (default len(a)) bound the\n\
206slice of a to be searched.\n");
207
208PyDoc_STRVAR(bisect_doc, "Alias for bisect_right().\n");
209PyDoc_STRVAR(insort_doc, "Alias for insort_right().\n");
210
211static PyMethodDef bisect_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000212 {"bisect_right", (PyCFunction)bisect_right,
213 METH_VARARGS|METH_KEYWORDS, bisect_right_doc},
214 {"bisect", (PyCFunction)bisect_right,
215 METH_VARARGS|METH_KEYWORDS, bisect_doc},
216 {"insort_right", (PyCFunction)insort_right,
217 METH_VARARGS|METH_KEYWORDS, insort_right_doc},
218 {"insort", (PyCFunction)insort_right,
219 METH_VARARGS|METH_KEYWORDS, insort_doc},
220 {"bisect_left", (PyCFunction)bisect_left,
221 METH_VARARGS|METH_KEYWORDS, bisect_left_doc},
222 {"insort_left", (PyCFunction)insort_left,
223 METH_VARARGS|METH_KEYWORDS, insort_left_doc},
224 {NULL, NULL} /* sentinel */
Raymond Hettinger0c410272004-01-05 10:13:35 +0000225};
226
227PyDoc_STRVAR(module_doc,
228"Bisection algorithms.\n\
229\n\
230This module provides support for maintaining a list in sorted order without\n\
231having to sort the list after each insertion. For long lists of items with\n\
232expensive comparison operations, this can be an improvement over the more\n\
233common approach.\n");
234
Raymond Hettinger0c410272004-01-05 10:13:35 +0000235
Martin v. Löwis1a214512008-06-11 05:26:20 +0000236static struct PyModuleDef _bisectmodule = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000237 PyModuleDef_HEAD_INIT,
238 "_bisect",
239 module_doc,
240 -1,
241 bisect_methods,
242 NULL,
243 NULL,
244 NULL,
245 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +0000246};
247
248PyMODINIT_FUNC
249PyInit__bisect(void)
250{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000251 return PyModule_Create(&_bisectmodule);
Raymond Hettinger0c410272004-01-05 10:13:35 +0000252}