blob: b6652c0ecb0883a23bf131436d8d63452dc72034 [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
Raymond Hettinger527eee22008-07-24 05:38:48 +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 Pitrouc83ea132010-05-09 14:46:46 +000011 PyObject *litem;
12 Py_ssize_t mid, res;
Raymond Hettinger0c410272004-01-05 10:13:35 +000013
Antoine Pitrouc83ea132010-05-09 14:46:46 +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) {
Mark Dickinson0407e962012-04-15 16:43:19 +010024 /* The (size_t)cast ensures that the addition and subsequent division
25 are performed as unsigned operations, avoiding difficulties from
26 signed overflow. (See issue 13496.) */
Mark Dickinson0407e962012-04-15 16:43:19 +010027 mid = ((size_t)lo + hi) / 2;
Antoine Pitrouc83ea132010-05-09 14:46:46 +000028 litem = PySequence_GetItem(list, mid);
29 if (litem == NULL)
30 return -1;
31 res = PyObject_RichCompareBool(item, litem, Py_LT);
32 Py_DECREF(litem);
33 if (res < 0)
34 return -1;
35 if (res)
36 hi = mid;
37 else
38 lo = mid + 1;
39 }
40 return lo;
Raymond Hettinger0c410272004-01-05 10:13:35 +000041}
42
43static PyObject *
Raymond Hettingercc9a9512005-10-05 11:39:12 +000044bisect_right(PyObject *self, PyObject *args, PyObject *kw)
Raymond Hettinger0c410272004-01-05 10:13:35 +000045{
Antoine Pitrouc83ea132010-05-09 14:46:46 +000046 PyObject *list, *item;
47 Py_ssize_t lo = 0;
48 Py_ssize_t hi = -1;
49 Py_ssize_t index;
50 static char *keywords[] = {"a", "x", "lo", "hi", NULL};
Raymond Hettinger0c410272004-01-05 10:13:35 +000051
Antoine Pitrouc83ea132010-05-09 14:46:46 +000052 if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|nn:bisect_right",
53 keywords, &list, &item, &lo, &hi))
54 return NULL;
55 index = internal_bisect_right(list, item, lo, hi);
56 if (index < 0)
57 return NULL;
58 return PyInt_FromSsize_t(index);
Raymond Hettinger0c410272004-01-05 10:13:35 +000059}
60
61PyDoc_STRVAR(bisect_right_doc,
Raymond Hettingera68bdc72012-04-27 00:20:39 -070062"bisect(a, x[, lo[, hi]]) -> index\n\
63bisect_right(a, x[, lo[, hi]]) -> index\n\
Raymond Hettinger0c410272004-01-05 10:13:35 +000064\n\
65Return the index where to insert item x in list a, assuming a is sorted.\n\
66\n\
67The return value i is such that all e in a[:i] have e <= x, and all e in\n\
68a[i:] have e > x. So if x already appears in the list, i points just\n\
69beyond the rightmost x already there\n\
70\n\
71Optional args lo (default 0) and hi (default len(a)) bound the\n\
72slice of a to be searched.\n");
73
74static PyObject *
Raymond Hettingercc9a9512005-10-05 11:39:12 +000075insort_right(PyObject *self, PyObject *args, PyObject *kw)
Raymond Hettinger0c410272004-01-05 10:13:35 +000076{
Antoine Pitrouc83ea132010-05-09 14:46:46 +000077 PyObject *list, *item, *result;
78 Py_ssize_t lo = 0;
79 Py_ssize_t hi = -1;
80 Py_ssize_t index;
81 static char *keywords[] = {"a", "x", "lo", "hi", NULL};
Raymond Hettinger0c410272004-01-05 10:13:35 +000082
Antoine Pitrouc83ea132010-05-09 14:46:46 +000083 if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|nn:insort_right",
84 keywords, &list, &item, &lo, &hi))
85 return NULL;
86 index = internal_bisect_right(list, item, lo, hi);
87 if (index < 0)
88 return NULL;
89 if (PyList_CheckExact(list)) {
90 if (PyList_Insert(list, index, item) < 0)
91 return NULL;
92 } else {
93 result = PyObject_CallMethod(list, "insert", "nO",
94 index, item);
95 if (result == NULL)
96 return NULL;
97 Py_DECREF(result);
98 }
Raymond Hettinger0c410272004-01-05 10:13:35 +000099
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000100 Py_RETURN_NONE;
Raymond Hettinger0c410272004-01-05 10:13:35 +0000101}
102
103PyDoc_STRVAR(insort_right_doc,
Raymond Hettingera68bdc72012-04-27 00:20:39 -0700104"insort(a, x[, lo[, hi]])\n\
105insort_right(a, x[, lo[, hi]])\n\
Raymond Hettinger0c410272004-01-05 10:13:35 +0000106\n\
107Insert item x in list a, and keep it sorted assuming a is sorted.\n\
108\n\
109If x is already in a, insert it to the right of the rightmost x.\n\
110\n\
111Optional args lo (default 0) and hi (default len(a)) bound the\n\
112slice of a to be searched.\n");
113
Raymond Hettinger527eee22008-07-24 05:38:48 +0000114static Py_ssize_t
115internal_bisect_left(PyObject *list, PyObject *item, Py_ssize_t lo, Py_ssize_t hi)
Raymond Hettinger0c410272004-01-05 10:13:35 +0000116{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000117 PyObject *litem;
118 Py_ssize_t mid, res;
Raymond Hettinger0c410272004-01-05 10:13:35 +0000119
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000120 if (lo < 0) {
121 PyErr_SetString(PyExc_ValueError, "lo must be non-negative");
122 return -1;
123 }
124 if (hi == -1) {
125 hi = PySequence_Size(list);
126 if (hi < 0)
127 return -1;
128 }
129 while (lo < hi) {
Mark Dickinson0407e962012-04-15 16:43:19 +0100130 /* The (size_t)cast ensures that the addition and subsequent division
131 are performed as unsigned operations, avoiding difficulties from
132 signed overflow. (See issue 13496.) */
133 mid = ((size_t)lo + hi) / 2;
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000134 litem = PySequence_GetItem(list, mid);
135 if (litem == NULL)
136 return -1;
137 res = PyObject_RichCompareBool(litem, item, Py_LT);
138 Py_DECREF(litem);
139 if (res < 0)
140 return -1;
141 if (res)
142 lo = mid + 1;
143 else
144 hi = mid;
145 }
146 return lo;
Raymond Hettinger0c410272004-01-05 10:13:35 +0000147}
148
149static PyObject *
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000150bisect_left(PyObject *self, PyObject *args, PyObject *kw)
Raymond Hettinger0c410272004-01-05 10:13:35 +0000151{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000152 PyObject *list, *item;
153 Py_ssize_t lo = 0;
154 Py_ssize_t hi = -1;
155 Py_ssize_t index;
156 static char *keywords[] = {"a", "x", "lo", "hi", NULL};
Raymond Hettinger0c410272004-01-05 10:13:35 +0000157
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000158 if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|nn:bisect_left",
159 keywords, &list, &item, &lo, &hi))
160 return NULL;
161 index = internal_bisect_left(list, item, lo, hi);
162 if (index < 0)
163 return NULL;
164 return PyInt_FromSsize_t(index);
Raymond Hettinger0c410272004-01-05 10:13:35 +0000165}
166
167PyDoc_STRVAR(bisect_left_doc,
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000168"bisect_left(a, x[, lo[, hi]]) -> index\n\
Raymond Hettinger0c410272004-01-05 10:13:35 +0000169\n\
170Return the index where to insert item x in list a, assuming a is sorted.\n\
171\n\
172The return value i is such that all e in a[:i] have e < x, and all e in\n\
173a[i:] have e >= x. So if x already appears in the list, i points just\n\
174before the leftmost x already there.\n\
175\n\
176Optional args lo (default 0) and hi (default len(a)) bound the\n\
177slice of a to be searched.\n");
178
179static PyObject *
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000180insort_left(PyObject *self, PyObject *args, PyObject *kw)
Raymond Hettinger0c410272004-01-05 10:13:35 +0000181{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000182 PyObject *list, *item, *result;
183 Py_ssize_t lo = 0;
184 Py_ssize_t hi = -1;
185 Py_ssize_t index;
186 static char *keywords[] = {"a", "x", "lo", "hi", NULL};
Raymond Hettinger0c410272004-01-05 10:13:35 +0000187
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000188 if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|nn:insort_left",
189 keywords, &list, &item, &lo, &hi))
190 return NULL;
191 index = internal_bisect_left(list, item, lo, hi);
192 if (index < 0)
193 return NULL;
194 if (PyList_CheckExact(list)) {
195 if (PyList_Insert(list, index, item) < 0)
196 return NULL;
197 } else {
Antoine Pitrou38fbd792012-05-16 15:01:40 +0200198 result = PyObject_CallMethod(list, "insert", "nO",
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000199 index, item);
200 if (result == NULL)
201 return NULL;
202 Py_DECREF(result);
203 }
Raymond Hettinger0c410272004-01-05 10:13:35 +0000204
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000205 Py_RETURN_NONE;
Raymond Hettinger0c410272004-01-05 10:13:35 +0000206}
207
208PyDoc_STRVAR(insort_left_doc,
Raymond Hettingercc9a9512005-10-05 11:39:12 +0000209"insort_left(a, x[, lo[, hi]])\n\
Raymond Hettinger0c410272004-01-05 10:13:35 +0000210\n\
211Insert item x in list a, and keep it sorted assuming a is sorted.\n\
212\n\
213If x is already in a, insert it to the left of the leftmost x.\n\
214\n\
215Optional args lo (default 0) and hi (default len(a)) bound the\n\
216slice of a to be searched.\n");
217
Raymond Hettinger0c410272004-01-05 10:13:35 +0000218static PyMethodDef bisect_methods[] = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000219 {"bisect_right", (PyCFunction)bisect_right,
220 METH_VARARGS|METH_KEYWORDS, bisect_right_doc},
221 {"bisect", (PyCFunction)bisect_right,
Raymond Hettingera68bdc72012-04-27 00:20:39 -0700222 METH_VARARGS|METH_KEYWORDS, bisect_right_doc},
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000223 {"insort_right", (PyCFunction)insort_right,
224 METH_VARARGS|METH_KEYWORDS, insort_right_doc},
225 {"insort", (PyCFunction)insort_right,
Raymond Hettingera68bdc72012-04-27 00:20:39 -0700226 METH_VARARGS|METH_KEYWORDS, insort_right_doc},
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000227 {"bisect_left", (PyCFunction)bisect_left,
228 METH_VARARGS|METH_KEYWORDS, bisect_left_doc},
229 {"insort_left", (PyCFunction)insort_left,
230 METH_VARARGS|METH_KEYWORDS, insort_left_doc},
231 {NULL, NULL} /* sentinel */
Raymond Hettinger0c410272004-01-05 10:13:35 +0000232};
233
234PyDoc_STRVAR(module_doc,
235"Bisection algorithms.\n\
236\n\
237This module provides support for maintaining a list in sorted order without\n\
238having to sort the list after each insertion. For long lists of items with\n\
239expensive comparison operations, this can be an improvement over the more\n\
240common approach.\n");
241
242PyMODINIT_FUNC
243init_bisect(void)
244{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000245 Py_InitModule3("_bisect", bisect_methods, module_doc);
Raymond Hettinger0c410272004-01-05 10:13:35 +0000246}