From acb75dcac4848e32b1f71241594ef2e93bc02c98 Mon Sep 17 00:00:00 2001 From: Wojtek Date: Wed, 17 Dec 2025 17:25:51 +0100 Subject: [PATCH] list tuple indexed access --- python_tests/test_list.py | 5 +++ .../bindings/python/collections/PyList.cpp | 42 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/python_tests/test_list.py b/python_tests/test_list.py index 78c27615..74b545ee 100644 --- a/python_tests/test_list.py +++ b/python_tests/test_list.py @@ -541,3 +541,8 @@ def test_append_to_random_lists(db0_autocommit_fixture): print(f"Prefix size = {db0.get_storage_stats()['prefix_size']} bytes") db0.commit() + + +def test_list_tuple_indexed_access(db0_fixture): + db0_list = db0.list([1, 2, 3, 5, 6, 7, 8]) + assert db0_list[(1, 3, 4)] == [2, 5, 6] diff --git a/src/dbzero/bindings/python/collections/PyList.cpp b/src/dbzero/bindings/python/collections/PyList.cpp index c1921126..42457302 100644 --- a/src/dbzero/bindings/python/collections/PyList.cpp +++ b/src/dbzero/bindings/python/collections/PyList.cpp @@ -108,6 +108,48 @@ namespace db0::python return py_src_list->ext().getItem(index).steal(); } + // check for tuple of indices + if (PyTuple_Check(elem)) { + Py_ssize_t num_items = PyTuple_Size(elem); + std::vector indices; + indices.reserve(num_items); + + // Extract indices from tuple + for (Py_ssize_t i = 0; i < num_items; ++i) { + PyObject *py_item = PyTuple_GetItem(elem, i); + if (!PyLong_Check(py_item)) { + THROWF(db0::InputException) << "Expected integer indexes in the tuple"; + } + auto index = PyLong_AsLongLong(py_item); + // Handle negative indices + if (index < 0) { + index += py_src_list->ext().size(); + } + if (index < 0 || static_cast(index) >= py_src_list->ext().size()) { + PyErr_SetString(PyExc_IndexError, "list index out of range"); + return nullptr; + } + indices.push_back(static_cast(index)); + } + + // Create result list + auto py_result = Py_OWN(PyList_New(num_items)); + if (!py_result) { + return nullptr; + } + + // Fetch items at specified indices + for (std::size_t i = 0; i < indices.size(); ++i) { + auto item = py_src_list->ext().getItem(indices[i]); + if (!item) { + return nullptr; + } + PySafeList_SetItem(*py_result, i, item); + } + + return py_result.steal(); + } + // Check if the key is a slice object if (PySlice_Check(elem)) { // Parse slice object to get start, stop, step