@@ -69,6 +69,10 @@ int SortedDict_init(SortedDict *self, PyObject *args, PyObject *kwds)
6969 }
7070
7171 PyObject * copy = PyDict_Copy (dict );
72+ if (!copy ) {
73+ return -1 ;
74+ }
75+
7276 if (self -> data ) {
7377 Py_DECREF (self -> data );
7478 }
@@ -77,7 +81,13 @@ int SortedDict_init(SortedDict *self, PyObject *args, PyObject *kwds)
7781
7882
7983 if (kwds && PyDict_Check (kwds ) && PyDict_Size (kwds ) > 0 ) {
80- if (PyDict_Contains (kwds , PyUnicode_FromString ("max_depth" ))) {
84+ PyObject * max_depth_string = PyUnicode_FromString ("max_depth" );
85+ if (!max_depth_string ) {
86+ return -1 ;
87+ }
88+
89+ if (PyDict_Contains (kwds , max_depth_string )) {
90+ Py_DECREF (max_depth_string );
8191 PyObject * max_depth = PyDict_GetItemString (kwds , "max_depth" );
8292 if (PyLong_Check (max_depth )) {
8393 self -> depth = PyLong_AsLong (max_depth );
@@ -94,9 +104,17 @@ int SortedDict_init(SortedDict *self, PyObject *args, PyObject *kwds)
94104 PyErr_SetString (PyExc_ValueError , "max_depth must be an integer" );
95105 return -1 ;
96106 }
107+ } else {
108+ Py_DECREF (max_depth_string );
97109 }
98110
99- if (PyDict_Contains (kwds , PyUnicode_FromString ("truncate" ))) {
111+ PyObject * truncate_string = PyUnicode_FromString ("truncate" );
112+ if (!truncate_string ) {
113+ return -1 ;
114+ }
115+
116+ if (PyDict_Contains (kwds , truncate_string )) {
117+ Py_DECREF (truncate_string );
100118 PyObject * truncate = PyDict_GetItemString (kwds , "truncate" );
101119
102120 if (PyBool_Check (truncate )) {
@@ -109,9 +127,17 @@ int SortedDict_init(SortedDict *self, PyObject *args, PyObject *kwds)
109127 PyErr_SetString (PyExc_ValueError , "truncate must be a boolean" );
110128 return -1 ;
111129 }
130+ } else {
131+ Py_DECREF (truncate_string );
132+ }
133+
134+ PyObject * ordering_string = PyUnicode_FromString ("ordering" );
135+ if (!ordering_string ) {
136+ return -1 ;
112137 }
113138
114- if (PyDict_Contains (kwds , PyUnicode_FromString ("ordering" ))) {
139+ if (PyDict_Contains (kwds , ordering_string )) {
140+ Py_DECREF (ordering_string );
115141 ordering = PyDict_GetItemString (kwds , "ordering" );
116142 if (!PyUnicode_Check (ordering )) {
117143 PyErr_SetString (PyExc_ValueError , "ordering must be a string" );
@@ -138,6 +164,7 @@ int SortedDict_init(SortedDict *self, PyObject *args, PyObject *kwds)
138164 }
139165 Py_DECREF (str );
140166 } else {
167+ Py_DECREF (ordering_string );
141168 // default is ascending
142169 self -> ordering = ASCENDING ;
143170 }
@@ -364,20 +391,23 @@ PyObject* SortedDict_tolist(SortedDict *self, PyObject *Py_UNUSED(ignored))
364391 // new reference
365392 PyObject * key = PySequence_GetItem (self -> keys , i );
366393 if (EXPECT (!key , 0 )) {
394+ Py_DECREF (ret );
367395 return NULL ;
368396 }
369397
370398 // borrowed reference
371399 PyObject * value = PyDict_GetItem (self -> data , key );
372400 if (EXPECT (!value , 0 )) {
373401 Py_DECREF (key );
402+ Py_DECREF (ret );
374403 return value ;
375404 }
376405
377406 // Build tuple of (i.e., key, value)
378407 PyObject * tuple_entry = PyTuple_New (2 );
379408 if (EXPECT (!tuple_entry , 0 )) {
380409 Py_DECREF (key );
410+ Py_DECREF (ret );
381411 return NULL ;
382412 }
383413 PyTuple_SET_ITEM (tuple_entry , 0 , key );
@@ -387,7 +417,7 @@ PyObject* SortedDict_tolist(SortedDict *self, PyObject *Py_UNUSED(ignored))
387417 // Add tuple to list
388418 PyList_SET_ITEM (ret , i , tuple_entry );
389419 }
390-
420+
391421 return ret ;
392422}
393423
@@ -410,6 +440,7 @@ PyObject* SortedDict_truncate(SortedDict *self, PyObject *Py_UNUSED(ignored))
410440 return NULL ;
411441 }
412442
443+ // Delete items beyond depth
413444 for (int i = 0 ; i < len ; ++ i ) {
414445 if (EXPECT (PyDict_DelItem (self -> data , PySequence_Fast_GET_ITEM (delete , i )) == -1 , 0 )) {
415446 Py_DECREF (delete );
@@ -418,12 +449,17 @@ PyObject* SortedDict_truncate(SortedDict *self, PyObject *Py_UNUSED(ignored))
418449 }
419450 Py_DECREF (delete );
420451
452+ // Optimization: Instead of marking dirty and re-sorting, just slice the keys tuple
453+ // since we already have sorted keys and only removed items from the end
421454 if (len > 0 ) {
422- self -> dirty = true;
423- }
424-
425- if (EXPECT (update_keys (self ), 0 )) {
426- return NULL ;
455+ PyObject * new_keys = PySequence_GetSlice (self -> keys , 0 , self -> depth );
456+ if (EXPECT (!new_keys , 0 )) {
457+ return NULL ;
458+ }
459+ Py_DECREF (self -> keys );
460+ self -> keys = new_keys ;
461+ // Keys are still sorted, so don't mark dirty
462+ self -> dirty = false;
427463 }
428464 }
429465
@@ -460,16 +496,27 @@ PyObject *SortedDict_getitem(SortedDict *self, PyObject *key)
460496int SortedDict_setitem (SortedDict * self , PyObject * key , PyObject * value )
461497{
462498 if (value ) {
463- if (EXPECT (PyDict_Contains (self -> data , key ) == 0 , 0 )) {
499+ int key_exists = PyDict_Contains (self -> data , key );
500+ if (EXPECT (key_exists == -1 , 0 )) {
501+ return -1 ; // Error occurred
502+ }
503+
504+ if (EXPECT (key_exists == 0 , 0 )) {
464505 self -> dirty = true;
465- }
506+ }
466507
467508 int ret = PyDict_SetItem (self -> data , key , value );
468509
469510 if (EXPECT (ret == -1 , 0 )) {
470511 return ret ;
471- } else if (EXPECT (self -> truncate && !SortedDict_truncate (self , NULL ), 0 )) {
472- return -1 ;
512+ }
513+
514+ // Optimization: Only truncate if dict size exceeds depth
515+ // This avoids redundant truncate calls when updating existing keys
516+ if (EXPECT (self -> truncate && self -> depth > 0 && PyDict_Size (self -> data ) > self -> depth , 0 )) {
517+ if (!SortedDict_truncate (self , NULL )) {
518+ return -1 ;
519+ }
473520 }
474521
475522 return ret ;
@@ -483,7 +530,7 @@ int SortedDict_setitem(SortedDict *self, PyObject *key, PyObject *value)
483530/* Seq Functions */
484531int SortedDict_contains (const SortedDict * self , PyObject * value )
485532{
486- return PySequence_Contains (self -> data , value );
533+ return PyDict_Contains (self -> data , value );
487534}
488535
489536/* iterator methods */
@@ -504,6 +551,11 @@ PyObject *SortedDict_next(SortedDict *self)
504551 }
505552
506553 Py_ssize_t size = PySequence_Fast_GET_SIZE (self -> keys );
554+ // Respect depth limit for consistency with keys(), to_dict(), etc.
555+ if (self -> depth > 0 && self -> depth < size ) {
556+ size = self -> depth ;
557+ }
558+
507559 if (EXPECT (size == 0 , 0 )){
508560 return NULL ;
509561 }
@@ -514,6 +566,11 @@ PyObject *SortedDict_next(SortedDict *self)
514566 } else {
515567 self -> iterator_index ++ ;
516568 Py_ssize_t size = PySequence_Fast_GET_SIZE (self -> keys );
569+ // Respect depth limit for consistency with keys(), to_dict(), etc.
570+ if (self -> depth > 0 && self -> depth < size ) {
571+ size = self -> depth ;
572+ }
573+
517574 if (size <= self -> iterator_index ) {
518575 self -> iterator_index = -1 ;
519576 return NULL ;
0 commit comments