17db96d56Sopenharmony_ci/* Bisection algorithms. Drop in replacement for bisect.py 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciConverted to C by Dmitry Vasiliev (dima at hlabs.spb.ru). 47db96d56Sopenharmony_ci*/ 57db96d56Sopenharmony_ci 67db96d56Sopenharmony_ci#define PY_SSIZE_T_CLEAN 77db96d56Sopenharmony_ci#include "Python.h" 87db96d56Sopenharmony_ci 97db96d56Sopenharmony_ci/*[clinic input] 107db96d56Sopenharmony_cimodule _bisect 117db96d56Sopenharmony_ci[clinic start generated code]*/ 127db96d56Sopenharmony_ci/*[clinic end generated code: output=da39a3ee5e6b4b0d input=4d56a2b2033b462b]*/ 137db96d56Sopenharmony_ci 147db96d56Sopenharmony_ci#include "clinic/_bisectmodule.c.h" 157db96d56Sopenharmony_ci 167db96d56Sopenharmony_citypedef struct { 177db96d56Sopenharmony_ci PyObject *str_insert; 187db96d56Sopenharmony_ci} bisect_state; 197db96d56Sopenharmony_ci 207db96d56Sopenharmony_cistatic inline bisect_state* 217db96d56Sopenharmony_ciget_bisect_state(PyObject *module) 227db96d56Sopenharmony_ci{ 237db96d56Sopenharmony_ci void *state = PyModule_GetState(module); 247db96d56Sopenharmony_ci assert(state != NULL); 257db96d56Sopenharmony_ci return (bisect_state *)state; 267db96d56Sopenharmony_ci} 277db96d56Sopenharmony_ci 287db96d56Sopenharmony_cistatic inline Py_ssize_t 297db96d56Sopenharmony_ciinternal_bisect_right(PyObject *list, PyObject *item, Py_ssize_t lo, Py_ssize_t hi, 307db96d56Sopenharmony_ci PyObject* key) 317db96d56Sopenharmony_ci{ 327db96d56Sopenharmony_ci PyObject *litem; 337db96d56Sopenharmony_ci Py_ssize_t mid; 347db96d56Sopenharmony_ci int res; 357db96d56Sopenharmony_ci 367db96d56Sopenharmony_ci if (lo < 0) { 377db96d56Sopenharmony_ci PyErr_SetString(PyExc_ValueError, "lo must be non-negative"); 387db96d56Sopenharmony_ci return -1; 397db96d56Sopenharmony_ci } 407db96d56Sopenharmony_ci if (hi == -1) { 417db96d56Sopenharmony_ci hi = PySequence_Size(list); 427db96d56Sopenharmony_ci if (hi < 0) 437db96d56Sopenharmony_ci return -1; 447db96d56Sopenharmony_ci } 457db96d56Sopenharmony_ci while (lo < hi) { 467db96d56Sopenharmony_ci /* The (size_t)cast ensures that the addition and subsequent division 477db96d56Sopenharmony_ci are performed as unsigned operations, avoiding difficulties from 487db96d56Sopenharmony_ci signed overflow. (See issue 13496.) */ 497db96d56Sopenharmony_ci mid = ((size_t)lo + hi) / 2; 507db96d56Sopenharmony_ci litem = PySequence_GetItem(list, mid); 517db96d56Sopenharmony_ci if (litem == NULL) 527db96d56Sopenharmony_ci return -1; 537db96d56Sopenharmony_ci if (key != Py_None) { 547db96d56Sopenharmony_ci PyObject *newitem = PyObject_CallOneArg(key, litem); 557db96d56Sopenharmony_ci if (newitem == NULL) { 567db96d56Sopenharmony_ci Py_DECREF(litem); 577db96d56Sopenharmony_ci return -1; 587db96d56Sopenharmony_ci } 597db96d56Sopenharmony_ci Py_SETREF(litem, newitem); 607db96d56Sopenharmony_ci } 617db96d56Sopenharmony_ci res = PyObject_RichCompareBool(item, litem, Py_LT); 627db96d56Sopenharmony_ci Py_DECREF(litem); 637db96d56Sopenharmony_ci if (res < 0) 647db96d56Sopenharmony_ci return -1; 657db96d56Sopenharmony_ci if (res) 667db96d56Sopenharmony_ci hi = mid; 677db96d56Sopenharmony_ci else 687db96d56Sopenharmony_ci lo = mid + 1; 697db96d56Sopenharmony_ci } 707db96d56Sopenharmony_ci return lo; 717db96d56Sopenharmony_ci} 727db96d56Sopenharmony_ci 737db96d56Sopenharmony_ci/*[clinic input] 747db96d56Sopenharmony_ci_bisect.bisect_right -> Py_ssize_t 757db96d56Sopenharmony_ci 767db96d56Sopenharmony_ci a: object 777db96d56Sopenharmony_ci x: object 787db96d56Sopenharmony_ci lo: Py_ssize_t = 0 797db96d56Sopenharmony_ci hi: Py_ssize_t(c_default='-1', accept={int, NoneType}) = None 807db96d56Sopenharmony_ci * 817db96d56Sopenharmony_ci key: object = None 827db96d56Sopenharmony_ci 837db96d56Sopenharmony_ciReturn the index where to insert item x in list a, assuming a is sorted. 847db96d56Sopenharmony_ci 857db96d56Sopenharmony_ciThe return value i is such that all e in a[:i] have e <= x, and all e in 867db96d56Sopenharmony_cia[i:] have e > x. So if x already appears in the list, a.insert(i, x) will 877db96d56Sopenharmony_ciinsert just after the rightmost x already there. 887db96d56Sopenharmony_ci 897db96d56Sopenharmony_ciOptional args lo (default 0) and hi (default len(a)) bound the 907db96d56Sopenharmony_cislice of a to be searched. 917db96d56Sopenharmony_ci[clinic start generated code]*/ 927db96d56Sopenharmony_ci 937db96d56Sopenharmony_cistatic Py_ssize_t 947db96d56Sopenharmony_ci_bisect_bisect_right_impl(PyObject *module, PyObject *a, PyObject *x, 957db96d56Sopenharmony_ci Py_ssize_t lo, Py_ssize_t hi, PyObject *key) 967db96d56Sopenharmony_ci/*[clinic end generated code: output=3a4bc09cc7c8a73d input=40fcc5afa06ae593]*/ 977db96d56Sopenharmony_ci{ 987db96d56Sopenharmony_ci return internal_bisect_right(a, x, lo, hi, key); 997db96d56Sopenharmony_ci} 1007db96d56Sopenharmony_ci 1017db96d56Sopenharmony_ci/*[clinic input] 1027db96d56Sopenharmony_ci_bisect.insort_right 1037db96d56Sopenharmony_ci 1047db96d56Sopenharmony_ci a: object 1057db96d56Sopenharmony_ci x: object 1067db96d56Sopenharmony_ci lo: Py_ssize_t = 0 1077db96d56Sopenharmony_ci hi: Py_ssize_t(c_default='-1', accept={int, NoneType}) = None 1087db96d56Sopenharmony_ci * 1097db96d56Sopenharmony_ci key: object = None 1107db96d56Sopenharmony_ci 1117db96d56Sopenharmony_ciInsert item x in list a, and keep it sorted assuming a is sorted. 1127db96d56Sopenharmony_ci 1137db96d56Sopenharmony_ciIf x is already in a, insert it to the right of the rightmost x. 1147db96d56Sopenharmony_ci 1157db96d56Sopenharmony_ciOptional args lo (default 0) and hi (default len(a)) bound the 1167db96d56Sopenharmony_cislice of a to be searched. 1177db96d56Sopenharmony_ci[clinic start generated code]*/ 1187db96d56Sopenharmony_ci 1197db96d56Sopenharmony_cistatic PyObject * 1207db96d56Sopenharmony_ci_bisect_insort_right_impl(PyObject *module, PyObject *a, PyObject *x, 1217db96d56Sopenharmony_ci Py_ssize_t lo, Py_ssize_t hi, PyObject *key) 1227db96d56Sopenharmony_ci/*[clinic end generated code: output=ac3bf26d07aedda2 input=44e1708e26b7b802]*/ 1237db96d56Sopenharmony_ci{ 1247db96d56Sopenharmony_ci PyObject *result, *key_x; 1257db96d56Sopenharmony_ci Py_ssize_t index; 1267db96d56Sopenharmony_ci 1277db96d56Sopenharmony_ci if (key == Py_None) { 1287db96d56Sopenharmony_ci index = internal_bisect_right(a, x, lo, hi, key); 1297db96d56Sopenharmony_ci } else { 1307db96d56Sopenharmony_ci key_x = PyObject_CallOneArg(key, x); 1317db96d56Sopenharmony_ci if (key_x == NULL) { 1327db96d56Sopenharmony_ci return NULL; 1337db96d56Sopenharmony_ci } 1347db96d56Sopenharmony_ci index = internal_bisect_right(a, key_x, lo, hi, key); 1357db96d56Sopenharmony_ci Py_DECREF(key_x); 1367db96d56Sopenharmony_ci } 1377db96d56Sopenharmony_ci if (index < 0) 1387db96d56Sopenharmony_ci return NULL; 1397db96d56Sopenharmony_ci if (PyList_CheckExact(a)) { 1407db96d56Sopenharmony_ci if (PyList_Insert(a, index, x) < 0) 1417db96d56Sopenharmony_ci return NULL; 1427db96d56Sopenharmony_ci } 1437db96d56Sopenharmony_ci else { 1447db96d56Sopenharmony_ci bisect_state *state = get_bisect_state(module); 1457db96d56Sopenharmony_ci result = _PyObject_CallMethod(a, state->str_insert, "nO", index, x); 1467db96d56Sopenharmony_ci if (result == NULL) 1477db96d56Sopenharmony_ci return NULL; 1487db96d56Sopenharmony_ci Py_DECREF(result); 1497db96d56Sopenharmony_ci } 1507db96d56Sopenharmony_ci 1517db96d56Sopenharmony_ci Py_RETURN_NONE; 1527db96d56Sopenharmony_ci} 1537db96d56Sopenharmony_ci 1547db96d56Sopenharmony_cistatic inline Py_ssize_t 1557db96d56Sopenharmony_ciinternal_bisect_left(PyObject *list, PyObject *item, Py_ssize_t lo, Py_ssize_t hi, 1567db96d56Sopenharmony_ci PyObject *key) 1577db96d56Sopenharmony_ci{ 1587db96d56Sopenharmony_ci PyObject *litem; 1597db96d56Sopenharmony_ci Py_ssize_t mid; 1607db96d56Sopenharmony_ci int res; 1617db96d56Sopenharmony_ci 1627db96d56Sopenharmony_ci if (lo < 0) { 1637db96d56Sopenharmony_ci PyErr_SetString(PyExc_ValueError, "lo must be non-negative"); 1647db96d56Sopenharmony_ci return -1; 1657db96d56Sopenharmony_ci } 1667db96d56Sopenharmony_ci if (hi == -1) { 1677db96d56Sopenharmony_ci hi = PySequence_Size(list); 1687db96d56Sopenharmony_ci if (hi < 0) 1697db96d56Sopenharmony_ci return -1; 1707db96d56Sopenharmony_ci } 1717db96d56Sopenharmony_ci while (lo < hi) { 1727db96d56Sopenharmony_ci /* The (size_t)cast ensures that the addition and subsequent division 1737db96d56Sopenharmony_ci are performed as unsigned operations, avoiding difficulties from 1747db96d56Sopenharmony_ci signed overflow. (See issue 13496.) */ 1757db96d56Sopenharmony_ci mid = ((size_t)lo + hi) / 2; 1767db96d56Sopenharmony_ci litem = PySequence_GetItem(list, mid); 1777db96d56Sopenharmony_ci if (litem == NULL) 1787db96d56Sopenharmony_ci return -1; 1797db96d56Sopenharmony_ci if (key != Py_None) { 1807db96d56Sopenharmony_ci PyObject *newitem = PyObject_CallOneArg(key, litem); 1817db96d56Sopenharmony_ci if (newitem == NULL) { 1827db96d56Sopenharmony_ci Py_DECREF(litem); 1837db96d56Sopenharmony_ci return -1; 1847db96d56Sopenharmony_ci } 1857db96d56Sopenharmony_ci Py_SETREF(litem, newitem); 1867db96d56Sopenharmony_ci } 1877db96d56Sopenharmony_ci res = PyObject_RichCompareBool(litem, item, Py_LT); 1887db96d56Sopenharmony_ci Py_DECREF(litem); 1897db96d56Sopenharmony_ci if (res < 0) 1907db96d56Sopenharmony_ci return -1; 1917db96d56Sopenharmony_ci if (res) 1927db96d56Sopenharmony_ci lo = mid + 1; 1937db96d56Sopenharmony_ci else 1947db96d56Sopenharmony_ci hi = mid; 1957db96d56Sopenharmony_ci } 1967db96d56Sopenharmony_ci return lo; 1977db96d56Sopenharmony_ci} 1987db96d56Sopenharmony_ci 1997db96d56Sopenharmony_ci 2007db96d56Sopenharmony_ci/*[clinic input] 2017db96d56Sopenharmony_ci_bisect.bisect_left -> Py_ssize_t 2027db96d56Sopenharmony_ci 2037db96d56Sopenharmony_ci a: object 2047db96d56Sopenharmony_ci x: object 2057db96d56Sopenharmony_ci lo: Py_ssize_t = 0 2067db96d56Sopenharmony_ci hi: Py_ssize_t(c_default='-1', accept={int, NoneType}) = None 2077db96d56Sopenharmony_ci * 2087db96d56Sopenharmony_ci key: object = None 2097db96d56Sopenharmony_ci 2107db96d56Sopenharmony_ciReturn the index where to insert item x in list a, assuming a is sorted. 2117db96d56Sopenharmony_ci 2127db96d56Sopenharmony_ciThe return value i is such that all e in a[:i] have e < x, and all e in 2137db96d56Sopenharmony_cia[i:] have e >= x. So if x already appears in the list, a.insert(i, x) will 2147db96d56Sopenharmony_ciinsert just before the leftmost x already there. 2157db96d56Sopenharmony_ci 2167db96d56Sopenharmony_ciOptional args lo (default 0) and hi (default len(a)) bound the 2177db96d56Sopenharmony_cislice of a to be searched. 2187db96d56Sopenharmony_ci[clinic start generated code]*/ 2197db96d56Sopenharmony_ci 2207db96d56Sopenharmony_cistatic Py_ssize_t 2217db96d56Sopenharmony_ci_bisect_bisect_left_impl(PyObject *module, PyObject *a, PyObject *x, 2227db96d56Sopenharmony_ci Py_ssize_t lo, Py_ssize_t hi, PyObject *key) 2237db96d56Sopenharmony_ci/*[clinic end generated code: output=70749d6e5cae9284 input=90dd35b50ceb05e3]*/ 2247db96d56Sopenharmony_ci{ 2257db96d56Sopenharmony_ci return internal_bisect_left(a, x, lo, hi, key); 2267db96d56Sopenharmony_ci} 2277db96d56Sopenharmony_ci 2287db96d56Sopenharmony_ci 2297db96d56Sopenharmony_ci/*[clinic input] 2307db96d56Sopenharmony_ci_bisect.insort_left 2317db96d56Sopenharmony_ci 2327db96d56Sopenharmony_ci a: object 2337db96d56Sopenharmony_ci x: object 2347db96d56Sopenharmony_ci lo: Py_ssize_t = 0 2357db96d56Sopenharmony_ci hi: Py_ssize_t(c_default='-1', accept={int, NoneType}) = None 2367db96d56Sopenharmony_ci * 2377db96d56Sopenharmony_ci key: object = None 2387db96d56Sopenharmony_ci 2397db96d56Sopenharmony_ciInsert item x in list a, and keep it sorted assuming a is sorted. 2407db96d56Sopenharmony_ci 2417db96d56Sopenharmony_ciIf x is already in a, insert it to the left of the leftmost x. 2427db96d56Sopenharmony_ci 2437db96d56Sopenharmony_ciOptional args lo (default 0) and hi (default len(a)) bound the 2447db96d56Sopenharmony_cislice of a to be searched. 2457db96d56Sopenharmony_ci[clinic start generated code]*/ 2467db96d56Sopenharmony_ci 2477db96d56Sopenharmony_cistatic PyObject * 2487db96d56Sopenharmony_ci_bisect_insort_left_impl(PyObject *module, PyObject *a, PyObject *x, 2497db96d56Sopenharmony_ci Py_ssize_t lo, Py_ssize_t hi, PyObject *key) 2507db96d56Sopenharmony_ci/*[clinic end generated code: output=b1d33e5e7ffff11e input=3ab65d8784f585b1]*/ 2517db96d56Sopenharmony_ci{ 2527db96d56Sopenharmony_ci PyObject *result, *key_x; 2537db96d56Sopenharmony_ci Py_ssize_t index; 2547db96d56Sopenharmony_ci 2557db96d56Sopenharmony_ci if (key == Py_None) { 2567db96d56Sopenharmony_ci index = internal_bisect_left(a, x, lo, hi, key); 2577db96d56Sopenharmony_ci } else { 2587db96d56Sopenharmony_ci key_x = PyObject_CallOneArg(key, x); 2597db96d56Sopenharmony_ci if (key_x == NULL) { 2607db96d56Sopenharmony_ci return NULL; 2617db96d56Sopenharmony_ci } 2627db96d56Sopenharmony_ci index = internal_bisect_left(a, key_x, lo, hi, key); 2637db96d56Sopenharmony_ci Py_DECREF(key_x); 2647db96d56Sopenharmony_ci } 2657db96d56Sopenharmony_ci if (index < 0) 2667db96d56Sopenharmony_ci return NULL; 2677db96d56Sopenharmony_ci if (PyList_CheckExact(a)) { 2687db96d56Sopenharmony_ci if (PyList_Insert(a, index, x) < 0) 2697db96d56Sopenharmony_ci return NULL; 2707db96d56Sopenharmony_ci } else { 2717db96d56Sopenharmony_ci bisect_state *state = get_bisect_state(module); 2727db96d56Sopenharmony_ci result = _PyObject_CallMethod(a, state->str_insert, "nO", index, x); 2737db96d56Sopenharmony_ci if (result == NULL) 2747db96d56Sopenharmony_ci return NULL; 2757db96d56Sopenharmony_ci Py_DECREF(result); 2767db96d56Sopenharmony_ci } 2777db96d56Sopenharmony_ci 2787db96d56Sopenharmony_ci Py_RETURN_NONE; 2797db96d56Sopenharmony_ci} 2807db96d56Sopenharmony_ci 2817db96d56Sopenharmony_cistatic PyMethodDef bisect_methods[] = { 2827db96d56Sopenharmony_ci _BISECT_BISECT_RIGHT_METHODDEF 2837db96d56Sopenharmony_ci _BISECT_INSORT_RIGHT_METHODDEF 2847db96d56Sopenharmony_ci _BISECT_BISECT_LEFT_METHODDEF 2857db96d56Sopenharmony_ci _BISECT_INSORT_LEFT_METHODDEF 2867db96d56Sopenharmony_ci {NULL, NULL} /* sentinel */ 2877db96d56Sopenharmony_ci}; 2887db96d56Sopenharmony_ci 2897db96d56Sopenharmony_ciPyDoc_STRVAR(module_doc, 2907db96d56Sopenharmony_ci"Bisection algorithms.\n\ 2917db96d56Sopenharmony_ci\n\ 2927db96d56Sopenharmony_ciThis module provides support for maintaining a list in sorted order without\n\ 2937db96d56Sopenharmony_cihaving to sort the list after each insertion. For long lists of items with\n\ 2947db96d56Sopenharmony_ciexpensive comparison operations, this can be an improvement over the more\n\ 2957db96d56Sopenharmony_cicommon approach.\n"); 2967db96d56Sopenharmony_ci 2977db96d56Sopenharmony_cistatic int 2987db96d56Sopenharmony_cibisect_clear(PyObject *module) 2997db96d56Sopenharmony_ci{ 3007db96d56Sopenharmony_ci bisect_state *state = get_bisect_state(module); 3017db96d56Sopenharmony_ci Py_CLEAR(state->str_insert); 3027db96d56Sopenharmony_ci return 0; 3037db96d56Sopenharmony_ci} 3047db96d56Sopenharmony_ci 3057db96d56Sopenharmony_cistatic void 3067db96d56Sopenharmony_cibisect_free(void *module) 3077db96d56Sopenharmony_ci{ 3087db96d56Sopenharmony_ci bisect_clear((PyObject *)module); 3097db96d56Sopenharmony_ci} 3107db96d56Sopenharmony_ci 3117db96d56Sopenharmony_cistatic int 3127db96d56Sopenharmony_cibisect_modexec(PyObject *m) 3137db96d56Sopenharmony_ci{ 3147db96d56Sopenharmony_ci bisect_state *state = get_bisect_state(m); 3157db96d56Sopenharmony_ci state->str_insert = PyUnicode_InternFromString("insert"); 3167db96d56Sopenharmony_ci if (state->str_insert == NULL) { 3177db96d56Sopenharmony_ci return -1; 3187db96d56Sopenharmony_ci } 3197db96d56Sopenharmony_ci return 0; 3207db96d56Sopenharmony_ci} 3217db96d56Sopenharmony_ci 3227db96d56Sopenharmony_cistatic PyModuleDef_Slot bisect_slots[] = { 3237db96d56Sopenharmony_ci {Py_mod_exec, bisect_modexec}, 3247db96d56Sopenharmony_ci {0, NULL} 3257db96d56Sopenharmony_ci}; 3267db96d56Sopenharmony_ci 3277db96d56Sopenharmony_cistatic struct PyModuleDef _bisectmodule = { 3287db96d56Sopenharmony_ci PyModuleDef_HEAD_INIT, 3297db96d56Sopenharmony_ci .m_name = "_bisect", 3307db96d56Sopenharmony_ci .m_size = sizeof(bisect_state), 3317db96d56Sopenharmony_ci .m_doc = module_doc, 3327db96d56Sopenharmony_ci .m_methods = bisect_methods, 3337db96d56Sopenharmony_ci .m_slots = bisect_slots, 3347db96d56Sopenharmony_ci .m_clear = bisect_clear, 3357db96d56Sopenharmony_ci .m_free = bisect_free, 3367db96d56Sopenharmony_ci}; 3377db96d56Sopenharmony_ci 3387db96d56Sopenharmony_ciPyMODINIT_FUNC 3397db96d56Sopenharmony_ciPyInit__bisect(void) 3407db96d56Sopenharmony_ci{ 3417db96d56Sopenharmony_ci return PyModuleDef_Init(&_bisectmodule); 3427db96d56Sopenharmony_ci} 343