@@ -2893,7 +2893,12 @@ order of two equal elements is maintained).
28932893If a key function is given, apply it once to each list item and sort them,
28942894ascending or descending, according to their function values.
28952895
2896+ Alternative to key function is supplying list to keylist argument,
2897+ which will determine sort order and will be modified in place.
2898+
28962899The reverse flag can be set to sort in descending order.
2900+
2901+ Both key and keylist can not be used at the same time.
28972902[clinic start generated code]*/
28982903
28992904static PyObject *
@@ -2911,6 +2916,11 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, PyObject *keylist,
29112916 PyObject * result = NULL ; /* guilty until proved innocent */
29122917 Py_ssize_t i ;
29132918 PyObject * * keys ;
2919+ // keylist vars
2920+ PyListObject * self_kl ;
2921+ Py_ssize_t keylist_ob_size , keylist_allocated ;
2922+ PyObject * * keylist_ob_item ;
2923+ int keylist_frozen = 0 ;
29142924
29152925 assert (self != NULL );
29162926 assert (PyList_Check (self ));
@@ -2926,12 +2936,6 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, PyObject *keylist,
29262936 "Only one of key and keylist can be provided." );
29272937 return result ;
29282938 }
2929- if (!PyList_Check (keylist )) {
2930- PyErr_Format (PyExc_TypeError ,
2931- "'%.200s' object is not list" ,
2932- Py_TYPE (keylist )-> tp_name );
2933- return result ;
2934- }
29352939 }
29362940
29372941 /* The list is temporarily made empty, so that mutations performed
@@ -2945,36 +2949,24 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, PyObject *keylist,
29452949 Py_SET_SIZE (self , 0 );
29462950 FT_ATOMIC_STORE_PTR_RELEASE (self -> ob_item , NULL );
29472951 self -> allocated = -1 ; /* any operation will reset it to >= 0 */
2948- PyObject * * keylist_ob_item ;
2952+
29492953 if (keyfunc == NULL && keylist == NULL ) {
29502954 keys = NULL ;
29512955 lo .keys = saved_ob_item ;
29522956 lo .values = NULL ;
29532957 }
29542958 else {
2955- if (saved_ob_size < MERGESTATE_TEMP_SIZE /2 )
2956- /* Leverage stack space we allocated but won't otherwise use */
2957- keys = & ms .temparray [saved_ob_size + 1 ];
2958- else {
2959- keys = PyMem_Malloc (sizeof (PyObject * ) * saved_ob_size );
2960- if (keys == NULL ) {
2961- PyErr_NoMemory ();
2962- goto keyfunc_fail ;
2963- }
2964- }
2965-
2966- if (keylist != NULL ) {
2967- if (saved_ob_size != Py_SIZE (keylist )) {
2968- PyErr_SetString (PyExc_ValueError ,
2969- "Lengths of input list and keylist differ." );
2970- goto keyfunc_fail ;
2971- }
2972- keylist_ob_item = ((PyListObject * ) keylist )-> ob_item ;
2973- for (i = 0 ; i < saved_ob_size ; i ++ ) {
2974- keys [i ] = keylist_ob_item [i ];
2959+ if (keyfunc != NULL ) {
2960+ if (saved_ob_size < MERGESTATE_TEMP_SIZE /2 )
2961+ /* Leverage stack space we allocated but won't otherwise use */
2962+ keys = & ms .temparray [saved_ob_size + 1 ];
2963+ else {
2964+ keys = PyMem_Malloc (sizeof (PyObject * ) * saved_ob_size );
2965+ if (keys == NULL ) {
2966+ PyErr_NoMemory ();
2967+ goto keyfunc_fail ;
2968+ }
29752969 }
2976- }
2977- else {
29782970 for (i = 0 ; i < saved_ob_size ; i ++ ) {
29792971 keys [i ] = PyObject_CallOneArg (keyfunc , saved_ob_item [i ]);
29802972 if (keys [i ] == NULL ) {
@@ -2986,11 +2978,34 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, PyObject *keylist,
29862978 }
29872979 }
29882980 }
2981+ else {
2982+ assert (keylist != NULL );
2983+ if (!PyList_Check (keylist )) {
2984+ PyErr_Format (PyExc_TypeError ,
2985+ "'%.200s' object is not a list" ,
2986+ Py_TYPE (keylist )-> tp_name );
2987+ goto keyfunc_fail ;
2988+ }
2989+ self_kl = ((PyListObject * ) keylist );
2990+ // Disable keylist modifications via same methodology as for main list
2991+ keylist_ob_size = Py_SIZE (self_kl );
2992+ keylist_ob_item = self_kl -> ob_item ;
2993+ keylist_allocated = self_kl -> allocated ;
2994+ Py_SET_SIZE (self_kl , 0 );
2995+ FT_ATOMIC_STORE_PTR_RELEASE (self_kl -> ob_item , NULL );
2996+ self_kl -> allocated = -1 ; /* any operation will reset it to >= 0 */
2997+
2998+ keylist_frozen = 1 ;
2999+ if (saved_ob_size != keylist_ob_size ) {
3000+ PyErr_SetString (PyExc_ValueError ,
3001+ "Lengths of input list and keylist differ." );
3002+ goto keylist_fail ;
3003+ }
3004+ keys = keylist_ob_item ;
3005+ }
29893006 lo .keys = keys ;
29903007 lo .values = saved_ob_item ;
29913008 }
2992-
2993-
29943009 /* The pre-sort check: here's where we decide which compare function to use.
29953010 * How much optimization is safe? We test for homogeneity with respect to
29963011 * several properties that are expensive to check at compare-time, and
@@ -3148,16 +3163,9 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, PyObject *keylist,
31483163succeed :
31493164 result = Py_None ;
31503165fail :
3151- if (keys != NULL ) {
3152- if (keylist != NULL ) {
3153- for (i = 0 ; i < saved_ob_size ; i ++ ) {
3154- keylist_ob_item [i ] = keys [i ];
3155- }
3156- }
3157- else {
3158- for (i = 0 ; i < saved_ob_size ; i ++ )
3159- Py_DECREF (keys [i ]);
3160- }
3166+ if (keyfunc != NULL ) {
3167+ for (i = 0 ; i < saved_ob_size ; i ++ )
3168+ Py_DECREF (keys [i ]);
31613169 if (saved_ob_size >= MERGESTATE_TEMP_SIZE /2 )
31623170 PyMem_Free (keys );
31633171 }
@@ -3175,6 +3183,40 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, PyObject *keylist,
31753183
31763184 merge_freemem (& ms );
31773185
3186+ keylist_fail :
3187+ if (keylist_frozen ) {
3188+ if (self_kl -> allocated != -1 && result != NULL ) {
3189+ /* The user mucked with the keylist during the sort,
3190+ * and we don't already have another error to report.
3191+ */
3192+ PyErr_SetString (PyExc_ValueError , "keylist modified during sort" );
3193+ result = NULL ;
3194+ }
3195+
3196+ if (reverse && saved_ob_size > 1 )
3197+ reverse_slice (keylist_ob_item , keylist_ob_item + keylist_ob_size );
3198+
3199+ final_ob_item = self_kl -> ob_item ;
3200+ i = Py_SIZE (self_kl );
3201+ Py_SET_SIZE (self_kl , keylist_ob_size );
3202+ FT_ATOMIC_STORE_PTR_RELEASE (self_kl -> ob_item , keylist_ob_item );
3203+ FT_ATOMIC_STORE_SSIZE_RELAXED (self_kl -> allocated , keylist_allocated );
3204+ if (final_ob_item != NULL ) {
3205+ /* we cannot use list_clear() for this because it does not
3206+ guarantee that the list is really empty when it returns */
3207+ while (-- i >= 0 ) {
3208+ Py_XDECREF (final_ob_item [i ]);
3209+ }
3210+ #ifdef Py_GIL_DISABLED
3211+ ensure_shared_on_resize (self_kl );
3212+ bool use_qsbr = _PyObject_GC_IS_SHARED (self_kl );
3213+ #else
3214+ bool use_qsbr = false;
3215+ #endif
3216+ free_list_items (final_ob_item , use_qsbr );
3217+ }
3218+ }
3219+
31783220keyfunc_fail :
31793221 final_ob_item = self -> ob_item ;
31803222 i = Py_SIZE (self );
0 commit comments