From c221cfe1f8925121a587123cf4bed378ec21e17a Mon Sep 17 00:00:00 2001 From: Vishal Pankaj Chandratreya <19171016+tfpf@users.noreply.github.com> Date: Thu, 19 Dec 2024 22:17:32 +0530 Subject: [PATCH 01/11] Removed custom initialisation and added `init` method [skip ci] --- src/pysorteddict/pysorteddict.cc | 57 ++++++++++++-------------------- 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/src/pysorteddict/pysorteddict.cc b/src/pysorteddict/pysorteddict.cc index db7264d..0045288 100644 --- a/src/pysorteddict/pysorteddict.cc +++ b/src/pysorteddict/pysorteddict.cc @@ -67,10 +67,10 @@ struct SortedDictType // Pointer to an object on the heap. Can't be the object itself, because // this container will be allocated a definite amount of space, which won't // allow the object to grow. - std::map* map = nullptr; + std::map* map; // The type of each key. - PyObject* key_type = nullptr; + PyObject* key_type; // These methods are named after the (Python or Python C API) functions // they are related to. Wherever there is no documentation comment above a @@ -87,6 +87,7 @@ struct SortedDictType PyObject* items(void); PyObject* keys(void); PyObject* values(void); + int init(PyObject*, PyObject*); }; /** @@ -316,6 +317,13 @@ PyObject* SortedDictType::values(void) return pyvalues; } +int SortedDictType::init(PyObject* args, PyObject* kwargs) +{ + this->map = new std::map; + this->key_type = nullptr; + return 0; +} + /****************************************************************************** * Code required to define the Python module and class can be found below this * point. Everything referenced therein is defined above in C++ style. @@ -327,7 +335,7 @@ PyObject* SortedDictType::values(void) static void sorted_dict_type_dealloc(PyObject* self) { SortedDictType* sd = reinterpret_cast(self); - Py_DECREF(sd->key_type); + Py_XDECREF(sd->key_type); sd->clear(); delete sd->map; Py_TYPE(self)->tp_free(self); @@ -514,39 +522,12 @@ static PyMethodDef sorted_dict_type_methods[] = { // clang-format on /** - * Allocate and initialise. + * Initialise. */ -static PyObject* sorted_dict_type_new(PyTypeObject* type, PyObject* args, PyObject* kwargs) +static int sorted_dict_type_init(PyObject* self, PyObject* args, PyObject* kwargs) { - // Up to Python 3.12, the argument parser below took an array of pointers - // (with each pointer pointing to a C string) as its fourth argument. - // However, C++ does not allow converting a string constant to a pointer. - // Hence, I use a character array to construct the C string, and then place - // it in an array of pointers. - char arg_name[] = "key_type"; - char* args_names[] = { arg_name, nullptr }; - PyObject* key_type; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|", args_names, &key_type)) - { - return nullptr; - } - - // Check the type to use for keys. - if (PyObject_RichCompareBool(key_type, reinterpret_cast(&PyLong_Type), Py_EQ) != 1) - { - PyErr_SetString(PyExc_TypeError, "constructor argument must be a supported type"); - return nullptr; - } - - PyObject* self = type->tp_alloc(type, 0); // New reference. - if (self == nullptr) - { - return nullptr; - } SortedDictType* sd = reinterpret_cast(self); - sd->map = new std::map; - sd->key_type = Py_NewRef(key_type); - return self; + return sd->init(args, kwargs); } PyDoc_STRVAR( @@ -593,10 +574,10 @@ static PyTypeObject sorted_dict_type = { nullptr, // tp_descr_get nullptr, // tp_descr_set 0, // tp_dictoffset - nullptr, // tp_init + sorted_dict_type_init, // tp_init PyType_GenericAlloc, // tp_alloc - sorted_dict_type_new, // tp_new - PyObject_Del, // tp_free + PyType_GenericNew, // tp_new + PyObject_Free, // tp_free nullptr, // tp_is_gc nullptr, // tp_bases nullptr, // tp_mro @@ -604,6 +585,10 @@ static PyTypeObject sorted_dict_type = { nullptr, // tp_subclasses nullptr, // tp_weaklist nullptr, // tp_del + 0, // tp_version_tag + nullptr, // tp_finalize + nullptr, // tp_vectorcall + 0, // tp_watched }; // clang-format on From c314c100e0e9dd182b8e6af4d6b9e0fc279a6f04 Mon Sep 17 00:00:00 2001 From: Vishal Pankaj Chandratreya <19171016+tfpf@users.noreply.github.com> Date: Thu, 19 Dec 2024 22:47:55 +0530 Subject: [PATCH 02/11] Added `finalise` method and restored allocator --- src/pysorteddict/pysorteddict.cc | 39 ++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/src/pysorteddict/pysorteddict.cc b/src/pysorteddict/pysorteddict.cc index 0045288..f634920 100644 --- a/src/pysorteddict/pysorteddict.cc +++ b/src/pysorteddict/pysorteddict.cc @@ -88,6 +88,7 @@ struct SortedDictType PyObject* keys(void); PyObject* values(void); int init(PyObject*, PyObject*); + void finalise(void); }; /** @@ -324,20 +325,27 @@ int SortedDictType::init(PyObject* args, PyObject* kwargs) return 0; } +void SortedDictType::finalise(void) +{ + Py_XDECREF(this->key_type); + for (auto& item : *this->map) + { + Py_DECREF(item.first); + Py_DECREF(item.second); + } + delete this->map; +} + /****************************************************************************** * Code required to define the Python module and class can be found below this * point. Everything referenced therein is defined above in C++ style. *****************************************************************************/ /** - * Deinitialise and deallocate. + * Deallocate. */ static void sorted_dict_type_dealloc(PyObject* self) { - SortedDictType* sd = reinterpret_cast(self); - Py_XDECREF(sd->key_type); - sd->clear(); - delete sd->map; Py_TYPE(self)->tp_free(self); } @@ -530,6 +538,23 @@ static int sorted_dict_type_init(PyObject* self, PyObject* args, PyObject* kwarg return sd->init(args, kwargs); } +/** + * Allocate. + */ +static PyObject* sorted_dict_type_new(PyTypeObject* type, PyObject* args, PyObject* kwargs) +{ + return type->tp_alloc(type, 0); +} + +/** + * Deinitialise. + */ +static void sorted_dict_type_finalise(PyObject* self) +{ + SortedDictType* sd = reinterpret_cast(self); + sd->finalise(); +} + PyDoc_STRVAR( sorted_dict_type_doc, "SortedDict(key_type: type) -> SortedDict\n" @@ -576,7 +601,7 @@ static PyTypeObject sorted_dict_type = { 0, // tp_dictoffset sorted_dict_type_init, // tp_init PyType_GenericAlloc, // tp_alloc - PyType_GenericNew, // tp_new + sorted_dict_type_new, // tp_new PyObject_Free, // tp_free nullptr, // tp_is_gc nullptr, // tp_bases @@ -586,7 +611,7 @@ static PyTypeObject sorted_dict_type = { nullptr, // tp_weaklist nullptr, // tp_del 0, // tp_version_tag - nullptr, // tp_finalize + sorted_dict_type_finalise, // tp_finalize nullptr, // tp_vectorcall 0, // tp_watched }; From 794946251f88c9576afd033224f8fea13d50a223 Mon Sep 17 00:00:00 2001 From: Vishal Pankaj Chandratreya <19171016+tfpf@users.noreply.github.com> Date: Thu, 19 Dec 2024 22:56:16 +0530 Subject: [PATCH 03/11] Added new reference comment --- src/pysorteddict/pysorteddict.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pysorteddict/pysorteddict.cc b/src/pysorteddict/pysorteddict.cc index f634920..d98ab5a 100644 --- a/src/pysorteddict/pysorteddict.cc +++ b/src/pysorteddict/pysorteddict.cc @@ -543,7 +543,7 @@ static int sorted_dict_type_init(PyObject* self, PyObject* args, PyObject* kwarg */ static PyObject* sorted_dict_type_new(PyTypeObject* type, PyObject* args, PyObject* kwargs) { - return type->tp_alloc(type, 0); + return type->tp_alloc(type, 0); // New reference. } /** From a40aa66b362f345790ae9991c46bc87a0a3825a2 Mon Sep 17 00:00:00 2001 From: Vishal Pankaj Chandratreya <19171016+tfpf@users.noreply.github.com> Date: Thu, 19 Dec 2024 23:07:32 +0530 Subject: [PATCH 04/11] Combined deallocation and finalisation as `tp_finalize` is not called https://stackoverflow.com/questions/78871472 --- examples/basic.py | 10 +--------- src/pysorteddict/pysorteddict.cc | 33 ++++++++++---------------------- 2 files changed, 11 insertions(+), 32 deletions(-) diff --git a/examples/basic.py b/examples/basic.py index efdf686..eb1127d 100755 --- a/examples/basic.py +++ b/examples/basic.py @@ -2,12 +2,4 @@ from pysorteddict import SortedDict -sd = SortedDict(int) - -sd[100] = "wut" -sd[1] = "ok" -sd[1] = "notok" -print(sd, len(sd)) -print(sd[1]) -print(sd.keys(), sd.values(), sd.items()) -del sd +sd = SortedDict() diff --git a/src/pysorteddict/pysorteddict.cc b/src/pysorteddict/pysorteddict.cc index d98ab5a..6ee6f59 100644 --- a/src/pysorteddict/pysorteddict.cc +++ b/src/pysorteddict/pysorteddict.cc @@ -88,7 +88,6 @@ struct SortedDictType PyObject* keys(void); PyObject* values(void); int init(PyObject*, PyObject*); - void finalise(void); }; /** @@ -325,27 +324,24 @@ int SortedDictType::init(PyObject* args, PyObject* kwargs) return 0; } -void SortedDictType::finalise(void) -{ - Py_XDECREF(this->key_type); - for (auto& item : *this->map) - { - Py_DECREF(item.first); - Py_DECREF(item.second); - } - delete this->map; -} - /****************************************************************************** * Code required to define the Python module and class can be found below this * point. Everything referenced therein is defined above in C++ style. *****************************************************************************/ /** - * Deallocate. + * Deinitialise and deallocate. */ static void sorted_dict_type_dealloc(PyObject* self) { + SortedDictType* sd = reinterpret_cast(self); + Py_XDECREF(sd->key_type); + for (auto& item : *sd->map) + { + Py_DECREF(item.first); + Py_DECREF(item.second); + } + delete sd->map; Py_TYPE(self)->tp_free(self); } @@ -546,15 +542,6 @@ static PyObject* sorted_dict_type_new(PyTypeObject* type, PyObject* args, PyObje return type->tp_alloc(type, 0); // New reference. } -/** - * Deinitialise. - */ -static void sorted_dict_type_finalise(PyObject* self) -{ - SortedDictType* sd = reinterpret_cast(self); - sd->finalise(); -} - PyDoc_STRVAR( sorted_dict_type_doc, "SortedDict(key_type: type) -> SortedDict\n" @@ -611,7 +598,7 @@ static PyTypeObject sorted_dict_type = { nullptr, // tp_weaklist nullptr, // tp_del 0, // tp_version_tag - sorted_dict_type_finalise, // tp_finalize + nullptr, // tp_finalize nullptr, // tp_vectorcall 0, // tp_watched }; From 41fa411ef69158fa9149b11405a5cee3d96598fd Mon Sep 17 00:00:00 2001 From: Vishal Pankaj Chandratreya <19171016+tfpf@users.noreply.github.com> Date: Fri, 20 Dec 2024 11:42:25 +0530 Subject: [PATCH 05/11] Added `update` method skeleton --- src/pysorteddict/pysorteddict.cc | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/pysorteddict/pysorteddict.cc b/src/pysorteddict/pysorteddict.cc index 6ee6f59..516ab5a 100644 --- a/src/pysorteddict/pysorteddict.cc +++ b/src/pysorteddict/pysorteddict.cc @@ -86,6 +86,7 @@ struct SortedDictType PyObject* copy(void); PyObject* items(void); PyObject* keys(void); + PyObject* update(PyObject*, PyObject*); PyObject* values(void); int init(PyObject*, PyObject*); }; @@ -317,6 +318,11 @@ PyObject* SortedDictType::values(void) return pyvalues; } +PyObject* SortedDictType::update(PyObject* args, PyObject* kwargs) +{ + Py_RETURN_NONE; +} + int SortedDictType::init(PyObject* args, PyObject* kwargs) { this->map = new std::map; @@ -474,6 +480,18 @@ static PyObject* sorted_dict_type_keys(PyObject* self, PyObject* args) return sd->keys(); } +PyDoc_STRVAR( + sorted_dict_type_update_doc, + "d.update(arg: Iterable[Iterable[object]], **kwargs)\n" + "Update the sorted dictionary ``d`` with the keys and values in ``arg`` and ``kwargs``." +); + +PyObject* sorted_dict_type_update(PyObject* self, PyObject* args, PyObject* kwargs) +{ + SortedDictType* sd = reinterpret_cast(self); + return sd->update(args, kwargs); +} + PyDoc_STRVAR( sorted_dict_type_values_doc, "d.values() -> list[object]\n" @@ -600,7 +618,6 @@ static PyTypeObject sorted_dict_type = { 0, // tp_version_tag nullptr, // tp_finalize nullptr, // tp_vectorcall - 0, // tp_watched }; // clang-format on @@ -630,7 +647,7 @@ PyMODINIT_FUNC PyInit_pysorteddict(void) { return nullptr; } - PyObject* mod = PyModule_Create(&sorted_dict_module); + PyObject* mod = PyModule_Create(&sorted_dict_module); // New reference. if (mod == nullptr) { return nullptr; From 76454ed7808b2b7a1f83ed7924616edece092df9 Mon Sep 17 00:00:00 2001 From: Vishal Pankaj Chandratreya <19171016+tfpf@users.noreply.github.com> Date: Fri, 20 Dec 2024 12:29:25 +0530 Subject: [PATCH 06/11] Used casts for `update` method --- src/pysorteddict/pysorteddict.cc | 55 +++++++++++++++++++------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/pysorteddict/pysorteddict.cc b/src/pysorteddict/pysorteddict.cc index 516ab5a..b24dac4 100644 --- a/src/pysorteddict/pysorteddict.cc +++ b/src/pysorteddict/pysorteddict.cc @@ -327,6 +327,10 @@ int SortedDictType::init(PyObject* args, PyObject* kwargs) { this->map = new std::map; this->key_type = nullptr; + if (this->update(args, kwargs) == nullptr) + { + return -1; + } return 0; } @@ -486,10 +490,9 @@ PyDoc_STRVAR( "Update the sorted dictionary ``d`` with the keys and values in ``arg`` and ``kwargs``." ); -PyObject* sorted_dict_type_update(PyObject* self, PyObject* args, PyObject* kwargs) +PyObject* sorted_dict_type_update(SortedDictType* self, PyObject* args, PyObject* kwargs) { - SortedDictType* sd = reinterpret_cast(self); - return sd->update(args, kwargs); + return self->update(args, kwargs); } PyDoc_STRVAR( @@ -508,34 +511,40 @@ static PyObject* sorted_dict_type_values(PyObject* self, PyObject* args) // clang-format off static PyMethodDef sorted_dict_type_methods[] = { { - "clear", // ml_name - sorted_dict_type_clear, // ml_meth - METH_NOARGS, // ml_flags - sorted_dict_type_clear_doc, // ml_doc + "clear", // ml_name + sorted_dict_type_clear, // ml_meth + METH_NOARGS, // ml_flags + sorted_dict_type_clear_doc, // ml_doc + }, + { + "copy", // ml_name + sorted_dict_type_copy, // ml_meth + METH_NOARGS, // ml_flags + sorted_dict_type_copy_doc, // ml_doc }, { - "copy", // ml_name - sorted_dict_type_copy, // ml_meth - METH_NOARGS, // ml_flags - sorted_dict_type_copy_doc, // ml_doc + "items", // ml_name + sorted_dict_type_items, // ml_meth + METH_NOARGS, // ml_flags + sorted_dict_type_items_doc, // ml_doc }, { - "items", // ml_name - sorted_dict_type_items, // ml_meth - METH_NOARGS, // ml_flags - sorted_dict_type_items_doc, // ml_doc + "keys", // ml_name + sorted_dict_type_keys, // ml_meth + METH_NOARGS, // ml_flags + sorted_dict_type_keys_doc, // ml_doc }, { - "keys", // ml_name - sorted_dict_type_keys, // ml_meth - METH_NOARGS, // ml_flags - sorted_dict_type_keys_doc, // ml_doc + "update", // ml_name + reinterpret_cast(sorted_dict_type_update), // ml_meth + METH_VARARGS | METH_KEYWORDS, // ml_flags + sorted_dict_type_update_doc, // ml_doc }, { - "values", // ml_name - sorted_dict_type_values, // ml_meth - METH_NOARGS, // ml_flags - sorted_dict_type_values_doc, // ml_doc + "values", // ml_name + sorted_dict_type_values, // ml_meth + METH_NOARGS, // ml_flags + sorted_dict_type_values_doc, // ml_doc }, { nullptr, From 7358df8654dea20c8ea128c2957577d391b23e44 Mon Sep 17 00:00:00 2001 From: Vishal Pankaj Chandratreya <19171016+tfpf@users.noreply.github.com> Date: Fri, 20 Dec 2024 14:14:25 +0530 Subject: [PATCH 07/11] Moved `update` definition to correct location --- src/pysorteddict/pysorteddict.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pysorteddict/pysorteddict.cc b/src/pysorteddict/pysorteddict.cc index b24dac4..33aa2eb 100644 --- a/src/pysorteddict/pysorteddict.cc +++ b/src/pysorteddict/pysorteddict.cc @@ -302,6 +302,11 @@ PyObject* SortedDictType::keys(void) return pykeys; } +PyObject* SortedDictType::update(PyObject* args, PyObject* kwargs) +{ + Py_RETURN_NONE; +} + PyObject* SortedDictType::values(void) { PyObject* pyvalues = PyList_New(this->map->size()); // New reference. @@ -318,11 +323,6 @@ PyObject* SortedDictType::values(void) return pyvalues; } -PyObject* SortedDictType::update(PyObject* args, PyObject* kwargs) -{ - Py_RETURN_NONE; -} - int SortedDictType::init(PyObject* args, PyObject* kwargs) { this->map = new std::map; From fad4c7daabf4fb3958893356c4db7c7661c44df1 Mon Sep 17 00:00:00 2001 From: Vishal Pankaj Chandratreya <19171016+tfpf@users.noreply.github.com> Date: Fri, 20 Dec 2024 14:31:14 +0530 Subject: [PATCH 08/11] Fixed method name in `PyArg_UnpackTuple` --- src/pysorteddict/pysorteddict.cc | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/pysorteddict/pysorteddict.cc b/src/pysorteddict/pysorteddict.cc index 33aa2eb..9694e37 100644 --- a/src/pysorteddict/pysorteddict.cc +++ b/src/pysorteddict/pysorteddict.cc @@ -86,7 +86,7 @@ struct SortedDictType PyObject* copy(void); PyObject* items(void); PyObject* keys(void); - PyObject* update(PyObject*, PyObject*); + PyObject* update(PyObject*, PyObject*, char const*); PyObject* values(void); int init(PyObject*, PyObject*); }; @@ -302,8 +302,22 @@ PyObject* SortedDictType::keys(void) return pykeys; } -PyObject* SortedDictType::update(PyObject* args, PyObject* kwargs) +/** + * Update with the given keys and values. + * + * @param args Positional arguments. + * @param kwargs Keyword arguments. + * @param name Python function which called this method. (For error reporting.) + * + * @return `None` on success, else `nullptr`. + */ +PyObject* SortedDictType::update(PyObject* args, PyObject* kwargs, char const* name = "update") { + PyObject* arg; + if (!PyArg_UnpackTuple(args, name, 0, 1, &arg)) + { + return nullptr; + } Py_RETURN_NONE; } @@ -327,7 +341,7 @@ int SortedDictType::init(PyObject* args, PyObject* kwargs) { this->map = new std::map; this->key_type = nullptr; - if (this->update(args, kwargs) == nullptr) + if (this->update(args, kwargs, "SortedDict") == nullptr) { return -1; } From c62046db189f35afcb0276230be2114a13eb43c4 Mon Sep 17 00:00:00 2001 From: Vishal Pankaj Chandratreya <19171016+tfpf@users.noreply.github.com> Date: Sat, 21 Dec 2024 15:05:47 +0530 Subject: [PATCH 09/11] Updated comments --- src/pysorteddict/pysorteddict.cc | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/pysorteddict/pysorteddict.cc b/src/pysorteddict/pysorteddict.cc index 9694e37..42e53dd 100644 --- a/src/pysorteddict/pysorteddict.cc +++ b/src/pysorteddict/pysorteddict.cc @@ -51,11 +51,10 @@ struct PyObject_CustomCompare bool operator()(PyObject* a, PyObject* b) const { // There must exist a total order on the set of possible keys. (Else, - // this comparison may error out.) Hence, only instances of the type - // passed to the constructor may be used as keys. (Instances of types - // derived from that type are not allowed, because comparisons between - // them may error out. See the constructor code.) With these - // precautions, this comparison should always work. + // this comparison may error out.) Hence, only instances of a single + // type may be used as keys. (Instances of types derived from it should + // not be allowed, because comparisons between them may error out.) + // With these precautions, this comparison should always work. return PyObject_RichCompareBool(a, b, Py_LT) == 1; } }; @@ -75,8 +74,6 @@ struct SortedDictType // These methods are named after the (Python or Python C API) functions // they are related to. Wherever there is no documentation comment above a // method, it means that that method is a proxy for the related function. - // In this scenario, the related function will be the caller of the method, - // and will have a similar name. bool is_type_key_type(PyObject*, bool); int contains(PyObject*); PyObject* getitem(PyObject*); From ff0c8ba87252d32e10a1be04158c633ee764deae Mon Sep 17 00:00:00 2001 From: Vishal Pankaj Chandratreya <19171016+tfpf@users.noreply.github.com> Date: Sat, 21 Dec 2024 15:09:58 +0530 Subject: [PATCH 10/11] Skeleton methods to update from parameters --- src/pysorteddict/pysorteddict.cc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/pysorteddict/pysorteddict.cc b/src/pysorteddict/pysorteddict.cc index 42e53dd..7291528 100644 --- a/src/pysorteddict/pysorteddict.cc +++ b/src/pysorteddict/pysorteddict.cc @@ -84,6 +84,8 @@ struct SortedDictType PyObject* items(void); PyObject* keys(void); PyObject* update(PyObject*, PyObject*, char const*); + PyObject* update_from_arg(PyObject*); + PyObject* update_from_kwargs(PyObject*); PyObject* values(void); int init(PyObject*, PyObject*); }; @@ -315,9 +317,25 @@ PyObject* SortedDictType::update(PyObject* args, PyObject* kwargs, char const* n { return nullptr; } + if (this->update_from_arg(arg) == nullptr) + { + return nullptr; + } + if (this->update_from_kwargs(kwargs) == nullptr) + { + return nullptr; + } Py_RETURN_NONE; } +PyObject* SortedDictType::update_from_arg(PyObject* arg) +{ +} + +PyObject* SortedDictType::update_from_kwargs(PyObject* arg) +{ +} + PyObject* SortedDictType::values(void) { PyObject* pyvalues = PyList_New(this->map->size()); // New reference. From 9ef12e6040c3e9385efb8092ab43b0ff60d4ffb2 Mon Sep 17 00:00:00 2001 From: Vishal Pankaj Chandratreya <19171016+tfpf@users.noreply.github.com> Date: Sat, 21 Dec 2024 15:47:18 +0530 Subject: [PATCH 11/11] Stub of `update` logic --- src/pysorteddict/pysorteddict.cc | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/pysorteddict/pysorteddict.cc b/src/pysorteddict/pysorteddict.cc index 7291528..ff30c5e 100644 --- a/src/pysorteddict/pysorteddict.cc +++ b/src/pysorteddict/pysorteddict.cc @@ -330,6 +330,38 @@ PyObject* SortedDictType::update(PyObject* args, PyObject* kwargs, char const* n PyObject* SortedDictType::update_from_arg(PyObject* arg) { + // Iterate over the keys. Obtain the mapped values. + PyObject *keys = PyMapping_Keys(arg); // New reference. + if(keys != nullptr){ + PyObject *iter = PyObject_GetIter(keys); // New reference. + Py_DECREF(keys); + if(iter == nullptr) + { + return nullptr; + } + while(true){ + PyObject *key = PyIter_Next(iter); // New reference. + // This can be a null pointer upon completion or an error. Hence, + // check for an error explicitly. + if(PyErr_Occurred() != nullptr) + { + Py_DECREF(iter); + return nullptr; + } + if(key == nullptr){ + Py_DECREF(iter); + Py_RETURN_NONE; + } + PyObject *value = PyObject_GetItem(arg, key); // New reference. + if(value == nullptr){ + Py_DECREF(key); + Py_DECREF(iter); + return nullptr; + } + // I need the getter and setter methods to do the type check. + // That should probably be in a separate pull request. + } + } } PyObject* SortedDictType::update_from_kwargs(PyObject* arg)