Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
98338227
Kaydet (Commit)
98338227
authored
Ara 02, 2010
tarafından
Daniel Stutzbach
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Issue9915: speeding up sorting with a key
üst
a0b44b5a
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
240 additions
and
225 deletions
+240
-225
NEWS
Misc/NEWS
+2
-0
listobject.c
Objects/listobject.c
+238
-225
No files found.
Misc/NEWS
Dosyayı görüntüle @
98338227
...
@@ -10,6 +10,8 @@ What's New in Python 3.2 Beta 1?
...
@@ -10,6 +10,8 @@ What's New in Python 3.2 Beta 1?
Core and Builtins
Core and Builtins
-----------------
-----------------
- Issue #9915: Speed up sorting with a key.
- Issue #9333: Expose os.symlink only when the SeCreateSymbolicLinkPrivilege
- Issue #9333: Expose os.symlink only when the SeCreateSymbolicLinkPrivilege
is held by the user's account, i.e., when the function can actually be used.
is held by the user's account, i.e., when the function can actually be used.
...
...
Objects/listobject.c
Dosyayı görüntüle @
98338227
...
@@ -940,6 +940,66 @@ reverse_slice(PyObject **lo, PyObject **hi)
...
@@ -940,6 +940,66 @@ reverse_slice(PyObject **lo, PyObject **hi)
* pieces to this algorithm; read listsort.txt for overviews and details.
* pieces to this algorithm; read listsort.txt for overviews and details.
*/
*/
/* A sortslice contains a pointer to an array of keys and a pointer to
* an array of corresponding values. In other words, keys[i]
* corresponds with values[i]. If values == NULL, then the keys are
* also the values.
*
* Several convenience routines are provided here, so that keys and
* values are always moved in sync.
*/
typedef
struct
{
PyObject
**
keys
;
PyObject
**
values
;
}
sortslice
;
Py_LOCAL_INLINE
(
void
)
sortslice_copy
(
sortslice
*
s1
,
Py_ssize_t
i
,
sortslice
*
s2
,
Py_ssize_t
j
)
{
s1
->
keys
[
i
]
=
s2
->
keys
[
j
];
if
(
s1
->
values
!=
NULL
)
s1
->
values
[
i
]
=
s2
->
values
[
j
];
}
Py_LOCAL_INLINE
(
void
)
sortslice_copy_incr
(
sortslice
*
dst
,
sortslice
*
src
)
{
*
dst
->
keys
++
=
*
src
->
keys
++
;
if
(
dst
->
values
!=
NULL
)
*
dst
->
values
++
=
*
src
->
values
++
;
}
Py_LOCAL_INLINE
(
void
)
sortslice_copy_decr
(
sortslice
*
dst
,
sortslice
*
src
)
{
*
dst
->
keys
--
=
*
src
->
keys
--
;
if
(
dst
->
values
!=
NULL
)
*
dst
->
values
--
=
*
src
->
values
--
;
}
Py_LOCAL_INLINE
(
void
)
sortslice_memcpy
(
sortslice
*
s1
,
Py_ssize_t
i
,
sortslice
*
s2
,
Py_ssize_t
j
,
Py_ssize_t
n
)
{
memcpy
(
&
s1
->
keys
[
i
],
&
s2
->
keys
[
j
],
sizeof
(
PyObject
*
)
*
n
);
if
(
s1
->
values
!=
NULL
)
memcpy
(
&
s1
->
values
[
i
],
&
s2
->
values
[
j
],
sizeof
(
PyObject
*
)
*
n
);
}
Py_LOCAL_INLINE
(
void
)
sortslice_memmove
(
sortslice
*
s1
,
Py_ssize_t
i
,
sortslice
*
s2
,
Py_ssize_t
j
,
Py_ssize_t
n
)
{
memmove
(
&
s1
->
keys
[
i
],
&
s2
->
keys
[
j
],
sizeof
(
PyObject
*
)
*
n
);
if
(
s1
->
values
!=
NULL
)
memmove
(
&
s1
->
values
[
i
],
&
s2
->
values
[
j
],
sizeof
(
PyObject
*
)
*
n
);
}
Py_LOCAL_INLINE
(
void
)
sortslice_advance
(
sortslice
*
slice
,
Py_ssize_t
n
)
{
slice
->
keys
+=
n
;
if
(
slice
->
values
!=
NULL
)
slice
->
values
+=
n
;
}
/* Comparison function: PyObject_RichCompareBool with Py_LT.
/* Comparison function: PyObject_RichCompareBool with Py_LT.
* Returns -1 on error, 1 if x < y, 0 if x >= y.
* Returns -1 on error, 1 if x < y, 0 if x >= y.
*/
*/
...
@@ -965,19 +1025,19 @@ reverse_slice(PyObject **lo, PyObject **hi)
...
@@ -965,19 +1025,19 @@ reverse_slice(PyObject **lo, PyObject **hi)
the input (nothing is lost or duplicated).
the input (nothing is lost or duplicated).
*/
*/
static
int
static
int
binarysort
(
PyObject
**
lo
,
PyObject
**
hi
,
PyObject
**
start
)
binarysort
(
sortslice
lo
,
PyObject
**
hi
,
PyObject
**
start
)
{
{
register
Py_ssize_t
k
;
register
Py_ssize_t
k
;
register
PyObject
**
l
,
**
p
,
**
r
;
register
PyObject
**
l
,
**
p
,
**
r
;
register
PyObject
*
pivot
;
register
PyObject
*
pivot
;
assert
(
lo
<=
start
&&
start
<=
hi
);
assert
(
lo
.
keys
<=
start
&&
start
<=
hi
);
/* assert [lo, start) is sorted */
/* assert [lo, start) is sorted */
if
(
lo
==
start
)
if
(
lo
.
keys
==
start
)
++
start
;
++
start
;
for
(;
start
<
hi
;
++
start
)
{
for
(;
start
<
hi
;
++
start
)
{
/* set l to where *start belongs */
/* set l to where *start belongs */
l
=
lo
;
l
=
lo
.
keys
;
r
=
start
;
r
=
start
;
pivot
=
*
r
;
pivot
=
*
r
;
/* Invariants:
/* Invariants:
...
@@ -1004,6 +1064,15 @@ binarysort(PyObject **lo, PyObject **hi, PyObject **start)
...
@@ -1004,6 +1064,15 @@ binarysort(PyObject **lo, PyObject **hi, PyObject **start)
for
(
p
=
start
;
p
>
l
;
--
p
)
for
(
p
=
start
;
p
>
l
;
--
p
)
*
p
=
*
(
p
-
1
);
*
p
=
*
(
p
-
1
);
*
l
=
pivot
;
*
l
=
pivot
;
if
(
lo
.
values
!=
NULL
)
{
Py_ssize_t
offset
=
lo
.
values
-
lo
.
keys
;
p
=
start
+
offset
;
pivot
=
*
p
;
l
+=
offset
;
for
(
p
=
start
+
offset
;
p
>
l
;
--
p
)
*
p
=
*
(
p
-
1
);
*
l
=
pivot
;
}
}
}
return
0
;
return
0
;
...
@@ -1272,7 +1341,7 @@ fail:
...
@@ -1272,7 +1341,7 @@ fail:
* a convenient way to pass state around among the helper functions.
* a convenient way to pass state around among the helper functions.
*/
*/
struct
s_slice
{
struct
s_slice
{
PyObject
**
base
;
sortslice
base
;
Py_ssize_t
len
;
Py_ssize_t
len
;
};
};
...
@@ -1286,7 +1355,7 @@ typedef struct s_MergeState {
...
@@ -1286,7 +1355,7 @@ typedef struct s_MergeState {
/* 'a' is temp storage to help with merges. It contains room for
/* 'a' is temp storage to help with merges. It contains room for
* alloced entries.
* alloced entries.
*/
*/
PyObject
**
a
;
/* may point to temparray below */
sortslice
a
;
/* may point to temparray below */
Py_ssize_t
alloced
;
Py_ssize_t
alloced
;
/* A stack of n pending runs yet to be merged. Run #i starts at
/* A stack of n pending runs yet to be merged. Run #i starts at
...
@@ -1307,11 +1376,29 @@ typedef struct s_MergeState {
...
@@ -1307,11 +1376,29 @@ typedef struct s_MergeState {
/* Conceptually a MergeState's constructor. */
/* Conceptually a MergeState's constructor. */
static
void
static
void
merge_init
(
MergeState
*
ms
)
merge_init
(
MergeState
*
ms
,
int
list_size
,
int
has_keyfunc
)
{
{
assert
(
ms
!=
NULL
);
assert
(
ms
!=
NULL
);
ms
->
a
=
ms
->
temparray
;
if
(
has_keyfunc
)
{
ms
->
alloced
=
MERGESTATE_TEMP_SIZE
;
/* The temporary space for merging will need at most half the list
* size rounded up. Use the minimum possible space so we can use the
* rest of temparray for other things. In particular, if there is
* enough extra space, listsort() will use it to store the keys.
*/
ms
->
alloced
=
(
list_size
+
1
)
/
2
;
/* ms->alloced describes how many keys will be stored at
ms->temparray, but we also need to store the values. Hence,
ms->alloced is capped at half of MERGESTATE_TEMP_SIZE. */
if
(
MERGESTATE_TEMP_SIZE
/
2
<
ms
->
alloced
)
ms
->
alloced
=
MERGESTATE_TEMP_SIZE
/
2
;
ms
->
a
.
values
=
&
ms
->
temparray
[
ms
->
alloced
];
}
else
{
ms
->
alloced
=
MERGESTATE_TEMP_SIZE
;
ms
->
a
.
values
=
NULL
;
}
ms
->
a
.
keys
=
ms
->
temparray
;
ms
->
n
=
0
;
ms
->
n
=
0
;
ms
->
min_gallop
=
MIN_GALLOP
;
ms
->
min_gallop
=
MIN_GALLOP
;
}
}
...
@@ -1324,10 +1411,8 @@ static void
...
@@ -1324,10 +1411,8 @@ static void
merge_freemem
(
MergeState
*
ms
)
merge_freemem
(
MergeState
*
ms
)
{
{
assert
(
ms
!=
NULL
);
assert
(
ms
!=
NULL
);
if
(
ms
->
a
!=
ms
->
temparray
)
if
(
ms
->
a
.
keys
!=
ms
->
temparray
)
PyMem_Free
(
ms
->
a
);
PyMem_Free
(
ms
->
a
.
keys
);
ms
->
a
=
ms
->
temparray
;
ms
->
alloced
=
MERGESTATE_TEMP_SIZE
;
}
}
/* Ensure enough temp memory for 'need' array slots is available.
/* Ensure enough temp memory for 'need' array slots is available.
...
@@ -1336,52 +1421,60 @@ merge_freemem(MergeState *ms)
...
@@ -1336,52 +1421,60 @@ merge_freemem(MergeState *ms)
static
int
static
int
merge_getmem
(
MergeState
*
ms
,
Py_ssize_t
need
)
merge_getmem
(
MergeState
*
ms
,
Py_ssize_t
need
)
{
{
int
multiplier
;
assert
(
ms
!=
NULL
);
assert
(
ms
!=
NULL
);
if
(
need
<=
ms
->
alloced
)
if
(
need
<=
ms
->
alloced
)
return
0
;
return
0
;
multiplier
=
ms
->
a
.
values
!=
NULL
?
2
:
1
;
/* Don't realloc! That can cost cycles to copy the old data, but
/* Don't realloc! That can cost cycles to copy the old data, but
* we don't care what's in the block.
* we don't care what's in the block.
*/
*/
merge_freemem
(
ms
);
merge_freemem
(
ms
);
if
((
size_t
)
need
>
PY_SSIZE_T_MAX
/
sizeof
(
PyObject
*
))
{
if
((
size_t
)
need
>
PY_SSIZE_T_MAX
/
sizeof
(
PyObject
*
)
/
multiplier
)
{
PyErr_NoMemory
();
PyErr_NoMemory
();
return
-
1
;
return
-
1
;
}
}
ms
->
a
=
(
PyObject
**
)
PyMem_Malloc
(
need
*
sizeof
(
PyObject
*
));
ms
->
a
.
keys
=
(
PyObject
**
)
PyMem_Malloc
(
multiplier
*
need
if
(
ms
->
a
)
{
*
sizeof
(
PyObject
*
));
if
(
ms
->
a
.
keys
!=
NULL
)
{
ms
->
alloced
=
need
;
ms
->
alloced
=
need
;
if
(
ms
->
a
.
values
!=
NULL
)
ms
->
a
.
values
=
&
ms
->
a
.
keys
[
need
];
return
0
;
return
0
;
}
}
PyErr_NoMemory
();
PyErr_NoMemory
();
merge_freemem
(
ms
);
/* reset to sane state */
return
-
1
;
return
-
1
;
}
}
#define MERGE_GETMEM(MS, NEED) ((NEED) <= (MS)->alloced ? 0 : \
#define MERGE_GETMEM(MS, NEED) ((NEED) <= (MS)->alloced ? 0 : \
merge_getmem(MS, NEED))
merge_getmem(MS, NEED))
/* Merge the na elements starting at
pa with the nb elements starting at pb
/* Merge the na elements starting at
ssa with the nb elements starting at
*
in a stable way, in-place. na and nb must be > 0, and pa + na == pb
.
*
ssb.keys = ssa.keys + na in a stable way, in-place. na and nb must be > 0
.
* Must also have that
*pb < *pa, that pa[na-1] belongs at the end of the
* Must also have that
ssa.keys[na-1] belongs at the end of the merge, and
*
merge, and should have na <= nb. See listsort.txt for more info.
*
should have na <= nb. See listsort.txt for more info. Return 0 if
*
Return 0 if
successful, -1 if error.
* successful, -1 if error.
*/
*/
static
Py_ssize_t
static
Py_ssize_t
merge_lo
(
MergeState
*
ms
,
PyObject
**
p
a
,
Py_ssize_t
na
,
merge_lo
(
MergeState
*
ms
,
sortslice
ss
a
,
Py_ssize_t
na
,
PyObject
**
p
b
,
Py_ssize_t
nb
)
sortslice
ss
b
,
Py_ssize_t
nb
)
{
{
Py_ssize_t
k
;
Py_ssize_t
k
;
PyObject
**
dest
;
sortslice
dest
;
int
result
=
-
1
;
/* guilty until proved innocent */
int
result
=
-
1
;
/* guilty until proved innocent */
Py_ssize_t
min_gallop
;
Py_ssize_t
min_gallop
;
assert
(
ms
&&
pa
&&
pb
&&
na
>
0
&&
nb
>
0
&&
pa
+
na
==
pb
);
assert
(
ms
&&
ssa
.
keys
&&
ssb
.
keys
&&
na
>
0
&&
nb
>
0
);
assert
(
ssa
.
keys
+
na
==
ssb
.
keys
);
if
(
MERGE_GETMEM
(
ms
,
na
)
<
0
)
if
(
MERGE_GETMEM
(
ms
,
na
)
<
0
)
return
-
1
;
return
-
1
;
memcpy
(
ms
->
a
,
pa
,
na
*
sizeof
(
PyObject
*
)
);
sortslice_memcpy
(
&
ms
->
a
,
0
,
&
ssa
,
0
,
na
);
dest
=
p
a
;
dest
=
ss
a
;
p
a
=
ms
->
a
;
ss
a
=
ms
->
a
;
*
dest
++
=
*
pb
++
;
sortslice_copy_incr
(
&
dest
,
&
ssb
)
;
--
nb
;
--
nb
;
if
(
nb
==
0
)
if
(
nb
==
0
)
goto
Succeed
;
goto
Succeed
;
...
@@ -1398,11 +1491,11 @@ merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na,
...
@@ -1398,11 +1491,11 @@ merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na,
*/
*/
for
(;;)
{
for
(;;)
{
assert
(
na
>
1
&&
nb
>
0
);
assert
(
na
>
1
&&
nb
>
0
);
k
=
ISLT
(
*
pb
,
*
pa
);
k
=
ISLT
(
ssb
.
keys
[
0
],
ssa
.
keys
[
0
]
);
if
(
k
)
{
if
(
k
)
{
if
(
k
<
0
)
if
(
k
<
0
)
goto
Fail
;
goto
Fail
;
*
dest
++
=
*
pb
++
;
sortslice_copy_incr
(
&
dest
,
&
ssb
)
;
++
bcount
;
++
bcount
;
acount
=
0
;
acount
=
0
;
--
nb
;
--
nb
;
...
@@ -1412,7 +1505,7 @@ merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na,
...
@@ -1412,7 +1505,7 @@ merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na,
break
;
break
;
}
}
else
{
else
{
*
dest
++
=
*
pa
++
;
sortslice_copy_incr
(
&
dest
,
&
ssa
)
;
++
acount
;
++
acount
;
bcount
=
0
;
bcount
=
0
;
--
na
;
--
na
;
...
@@ -1433,14 +1526,14 @@ merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na,
...
@@ -1433,14 +1526,14 @@ merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na,
assert
(
na
>
1
&&
nb
>
0
);
assert
(
na
>
1
&&
nb
>
0
);
min_gallop
-=
min_gallop
>
1
;
min_gallop
-=
min_gallop
>
1
;
ms
->
min_gallop
=
min_gallop
;
ms
->
min_gallop
=
min_gallop
;
k
=
gallop_right
(
*
pb
,
pa
,
na
,
0
);
k
=
gallop_right
(
ssb
.
keys
[
0
],
ssa
.
keys
,
na
,
0
);
acount
=
k
;
acount
=
k
;
if
(
k
)
{
if
(
k
)
{
if
(
k
<
0
)
if
(
k
<
0
)
goto
Fail
;
goto
Fail
;
memcpy
(
dest
,
pa
,
k
*
sizeof
(
PyObject
*
)
);
sortslice_memcpy
(
&
dest
,
0
,
&
ssa
,
0
,
k
);
dest
+=
k
;
sortslice_advance
(
&
dest
,
k
)
;
pa
+=
k
;
sortslice_advance
(
&
ssa
,
k
)
;
na
-=
k
;
na
-=
k
;
if
(
na
==
1
)
if
(
na
==
1
)
goto
CopyB
;
goto
CopyB
;
...
@@ -1451,24 +1544,24 @@ merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na,
...
@@ -1451,24 +1544,24 @@ merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na,
if
(
na
==
0
)
if
(
na
==
0
)
goto
Succeed
;
goto
Succeed
;
}
}
*
dest
++
=
*
pb
++
;
sortslice_copy_incr
(
&
dest
,
&
ssb
)
;
--
nb
;
--
nb
;
if
(
nb
==
0
)
if
(
nb
==
0
)
goto
Succeed
;
goto
Succeed
;
k
=
gallop_left
(
*
pa
,
pb
,
nb
,
0
);
k
=
gallop_left
(
ssa
.
keys
[
0
],
ssb
.
keys
,
nb
,
0
);
bcount
=
k
;
bcount
=
k
;
if
(
k
)
{
if
(
k
)
{
if
(
k
<
0
)
if
(
k
<
0
)
goto
Fail
;
goto
Fail
;
memmove
(
dest
,
pb
,
k
*
sizeof
(
PyObject
*
)
);
sortslice_memmove
(
&
dest
,
0
,
&
ssb
,
0
,
k
);
dest
+=
k
;
sortslice_advance
(
&
dest
,
k
)
;
pb
+=
k
;
sortslice_advance
(
&
ssb
,
k
)
;
nb
-=
k
;
nb
-=
k
;
if
(
nb
==
0
)
if
(
nb
==
0
)
goto
Succeed
;
goto
Succeed
;
}
}
*
dest
++
=
*
pa
++
;
sortslice_copy_incr
(
&
dest
,
&
ssa
)
;
--
na
;
--
na
;
if
(
na
==
1
)
if
(
na
==
1
)
goto
CopyB
;
goto
CopyB
;
...
@@ -1480,43 +1573,46 @@ Succeed:
...
@@ -1480,43 +1573,46 @@ Succeed:
result
=
0
;
result
=
0
;
Fail:
Fail:
if
(
na
)
if
(
na
)
memcpy
(
dest
,
pa
,
na
*
sizeof
(
PyObject
*
)
);
sortslice_memcpy
(
&
dest
,
0
,
&
ssa
,
0
,
na
);
return
result
;
return
result
;
CopyB:
CopyB:
assert
(
na
==
1
&&
nb
>
0
);
assert
(
na
==
1
&&
nb
>
0
);
/* The last element of
p
a belongs at the end of the merge. */
/* The last element of
ss
a belongs at the end of the merge. */
memmove
(
dest
,
pb
,
nb
*
sizeof
(
PyObject
*
)
);
sortslice_memmove
(
&
dest
,
0
,
&
ssb
,
0
,
nb
);
dest
[
nb
]
=
*
pa
;
sortslice_copy
(
&
dest
,
nb
,
&
ssa
,
0
)
;
return
0
;
return
0
;
}
}
/* Merge the na elements starting at pa with the nb elements starting at
pb
/* Merge the na elements starting at pa with the nb elements starting at
*
in a stable way, in-place. na and nb must be > 0, and pa + na == pb
.
*
ssb.keys = ssa.keys + na in a stable way, in-place. na and nb must be > 0
.
* Must also have that
*pb < *pa, that pa[na-1] belongs at the end of the
* Must also have that
ssa.keys[na-1] belongs at the end of the merge, and
*
merge, and should have na >= nb. See listsort.txt for more info.
*
should have na >= nb. See listsort.txt for more info. Return 0 if
*
Return 0 if
successful, -1 if error.
* successful, -1 if error.
*/
*/
static
Py_ssize_t
static
Py_ssize_t
merge_hi
(
MergeState
*
ms
,
PyObject
**
pa
,
Py_ssize_t
na
,
PyObject
**
pb
,
Py_ssize_t
nb
)
merge_hi
(
MergeState
*
ms
,
sortslice
ssa
,
Py_ssize_t
na
,
sortslice
ssb
,
Py_ssize_t
nb
)
{
{
Py_ssize_t
k
;
Py_ssize_t
k
;
PyObject
**
dest
;
sortslice
dest
,
basea
,
baseb
;
int
result
=
-
1
;
/* guilty until proved innocent */
int
result
=
-
1
;
/* guilty until proved innocent */
PyObject
**
basea
;
PyObject
**
baseb
;
Py_ssize_t
min_gallop
;
Py_ssize_t
min_gallop
;
assert
(
ms
&&
pa
&&
pb
&&
na
>
0
&&
nb
>
0
&&
pa
+
na
==
pb
);
assert
(
ms
&&
ssa
.
keys
&&
ssb
.
keys
&&
na
>
0
&&
nb
>
0
);
assert
(
ssa
.
keys
+
na
==
ssb
.
keys
);
if
(
MERGE_GETMEM
(
ms
,
nb
)
<
0
)
if
(
MERGE_GETMEM
(
ms
,
nb
)
<
0
)
return
-
1
;
return
-
1
;
dest
=
pb
+
nb
-
1
;
dest
=
ssb
;
memcpy
(
ms
->
a
,
pb
,
nb
*
sizeof
(
PyObject
*
));
sortslice_advance
(
&
dest
,
nb
-
1
);
basea
=
pa
;
sortslice_memcpy
(
&
ms
->
a
,
0
,
&
ssb
,
0
,
nb
);
basea
=
ssa
;
baseb
=
ms
->
a
;
baseb
=
ms
->
a
;
pb
=
ms
->
a
+
nb
-
1
;
ssb
.
keys
=
ms
->
a
.
keys
+
nb
-
1
;
pa
+=
na
-
1
;
if
(
ssb
.
values
!=
NULL
)
ssb
.
values
=
ms
->
a
.
values
+
nb
-
1
;
sortslice_advance
(
&
ssa
,
na
-
1
);
*
dest
--
=
*
pa
--
;
sortslice_copy_decr
(
&
dest
,
&
ssa
)
;
--
na
;
--
na
;
if
(
na
==
0
)
if
(
na
==
0
)
goto
Succeed
;
goto
Succeed
;
...
@@ -1533,11 +1629,11 @@ merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t
...
@@ -1533,11 +1629,11 @@ merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t
*/
*/
for
(;;)
{
for
(;;)
{
assert
(
na
>
0
&&
nb
>
1
);
assert
(
na
>
0
&&
nb
>
1
);
k
=
ISLT
(
*
pb
,
*
pa
);
k
=
ISLT
(
ssb
.
keys
[
0
],
ssa
.
keys
[
0
]
);
if
(
k
)
{
if
(
k
)
{
if
(
k
<
0
)
if
(
k
<
0
)
goto
Fail
;
goto
Fail
;
*
dest
--
=
*
pa
--
;
sortslice_copy_decr
(
&
dest
,
&
ssa
)
;
++
acount
;
++
acount
;
bcount
=
0
;
bcount
=
0
;
--
na
;
--
na
;
...
@@ -1547,7 +1643,7 @@ merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t
...
@@ -1547,7 +1643,7 @@ merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t
break
;
break
;
}
}
else
{
else
{
*
dest
--
=
*
pb
--
;
sortslice_copy_decr
(
&
dest
,
&
ssb
)
;
++
bcount
;
++
bcount
;
acount
=
0
;
acount
=
0
;
--
nb
;
--
nb
;
...
@@ -1568,33 +1664,33 @@ merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t
...
@@ -1568,33 +1664,33 @@ merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t
assert
(
na
>
0
&&
nb
>
1
);
assert
(
na
>
0
&&
nb
>
1
);
min_gallop
-=
min_gallop
>
1
;
min_gallop
-=
min_gallop
>
1
;
ms
->
min_gallop
=
min_gallop
;
ms
->
min_gallop
=
min_gallop
;
k
=
gallop_right
(
*
pb
,
basea
,
na
,
na
-
1
);
k
=
gallop_right
(
ssb
.
keys
[
0
],
basea
.
keys
,
na
,
na
-
1
);
if
(
k
<
0
)
if
(
k
<
0
)
goto
Fail
;
goto
Fail
;
k
=
na
-
k
;
k
=
na
-
k
;
acount
=
k
;
acount
=
k
;
if
(
k
)
{
if
(
k
)
{
dest
-=
k
;
sortslice_advance
(
&
dest
,
-
k
)
;
pa
-=
k
;
sortslice_advance
(
&
ssa
,
-
k
)
;
memmove
(
dest
+
1
,
pa
+
1
,
k
*
sizeof
(
PyObject
*
)
);
sortslice_memmove
(
&
dest
,
1
,
&
ssa
,
1
,
k
);
na
-=
k
;
na
-=
k
;
if
(
na
==
0
)
if
(
na
==
0
)
goto
Succeed
;
goto
Succeed
;
}
}
*
dest
--
=
*
pb
--
;
sortslice_copy_decr
(
&
dest
,
&
ssb
)
;
--
nb
;
--
nb
;
if
(
nb
==
1
)
if
(
nb
==
1
)
goto
CopyA
;
goto
CopyA
;
k
=
gallop_left
(
*
pa
,
baseb
,
nb
,
nb
-
1
);
k
=
gallop_left
(
ssa
.
keys
[
0
],
baseb
.
keys
,
nb
,
nb
-
1
);
if
(
k
<
0
)
if
(
k
<
0
)
goto
Fail
;
goto
Fail
;
k
=
nb
-
k
;
k
=
nb
-
k
;
bcount
=
k
;
bcount
=
k
;
if
(
k
)
{
if
(
k
)
{
dest
-=
k
;
sortslice_advance
(
&
dest
,
-
k
)
;
pb
-=
k
;
sortslice_advance
(
&
ssb
,
-
k
)
;
memcpy
(
dest
+
1
,
pb
+
1
,
k
*
sizeof
(
PyObject
*
)
);
sortslice_memcpy
(
&
dest
,
1
,
&
ssb
,
1
,
k
);
nb
-=
k
;
nb
-=
k
;
if
(
nb
==
1
)
if
(
nb
==
1
)
goto
CopyA
;
goto
CopyA
;
...
@@ -1605,7 +1701,7 @@ merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t
...
@@ -1605,7 +1701,7 @@ merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t
if
(
nb
==
0
)
if
(
nb
==
0
)
goto
Succeed
;
goto
Succeed
;
}
}
*
dest
--
=
*
pa
--
;
sortslice_copy_decr
(
&
dest
,
&
ssa
)
;
--
na
;
--
na
;
if
(
na
==
0
)
if
(
na
==
0
)
goto
Succeed
;
goto
Succeed
;
...
@@ -1617,15 +1713,15 @@ Succeed:
...
@@ -1617,15 +1713,15 @@ Succeed:
result
=
0
;
result
=
0
;
Fail:
Fail:
if
(
nb
)
if
(
nb
)
memcpy
(
dest
-
(
nb
-
1
),
baseb
,
nb
*
sizeof
(
PyObject
*
)
);
sortslice_memcpy
(
&
dest
,
-
(
nb
-
1
),
&
baseb
,
0
,
nb
);
return
result
;
return
result
;
CopyA:
CopyA:
assert
(
nb
==
1
&&
na
>
0
);
assert
(
nb
==
1
&&
na
>
0
);
/* The first element of
p
b belongs at the front of the merge. */
/* The first element of
ss
b belongs at the front of the merge. */
dest
-=
na
;
sortslice_memmove
(
&
dest
,
1
-
na
,
&
ssa
,
1
-
na
,
na
)
;
pa
-=
na
;
sortslice_advance
(
&
dest
,
-
na
)
;
memmove
(
dest
+
1
,
pa
+
1
,
na
*
sizeof
(
PyObject
*
)
);
sortslice_advance
(
&
ssa
,
-
na
);
*
dest
=
*
pb
;
sortslice_copy
(
&
dest
,
0
,
&
ssb
,
0
)
;
return
0
;
return
0
;
}
}
...
@@ -1635,7 +1731,7 @@ CopyA:
...
@@ -1635,7 +1731,7 @@ CopyA:
static
Py_ssize_t
static
Py_ssize_t
merge_at
(
MergeState
*
ms
,
Py_ssize_t
i
)
merge_at
(
MergeState
*
ms
,
Py_ssize_t
i
)
{
{
PyObject
**
pa
,
**
p
b
;
sortslice
ssa
,
ss
b
;
Py_ssize_t
na
,
nb
;
Py_ssize_t
na
,
nb
;
Py_ssize_t
k
;
Py_ssize_t
k
;
...
@@ -1644,12 +1740,12 @@ merge_at(MergeState *ms, Py_ssize_t i)
...
@@ -1644,12 +1740,12 @@ merge_at(MergeState *ms, Py_ssize_t i)
assert
(
i
>=
0
);
assert
(
i
>=
0
);
assert
(
i
==
ms
->
n
-
2
||
i
==
ms
->
n
-
3
);
assert
(
i
==
ms
->
n
-
2
||
i
==
ms
->
n
-
3
);
p
a
=
ms
->
pending
[
i
].
base
;
ss
a
=
ms
->
pending
[
i
].
base
;
na
=
ms
->
pending
[
i
].
len
;
na
=
ms
->
pending
[
i
].
len
;
p
b
=
ms
->
pending
[
i
+
1
].
base
;
ss
b
=
ms
->
pending
[
i
+
1
].
base
;
nb
=
ms
->
pending
[
i
+
1
].
len
;
nb
=
ms
->
pending
[
i
+
1
].
len
;
assert
(
na
>
0
&&
nb
>
0
);
assert
(
na
>
0
&&
nb
>
0
);
assert
(
pa
+
na
==
pb
);
assert
(
ssa
.
keys
+
na
==
ssb
.
keys
);
/* Record the length of the combined runs; if i is the 3rd-last
/* Record the length of the combined runs; if i is the 3rd-last
* run now, also slide over the last run (which isn't involved
* run now, also slide over the last run (which isn't involved
...
@@ -1663,10 +1759,10 @@ merge_at(MergeState *ms, Py_ssize_t i)
...
@@ -1663,10 +1759,10 @@ merge_at(MergeState *ms, Py_ssize_t i)
/* Where does b start in a? Elements in a before that can be
/* Where does b start in a? Elements in a before that can be
* ignored (already in place).
* ignored (already in place).
*/
*/
k
=
gallop_right
(
*
pb
,
pa
,
na
,
0
);
k
=
gallop_right
(
*
ssb
.
keys
,
ssa
.
keys
,
na
,
0
);
if
(
k
<
0
)
if
(
k
<
0
)
return
-
1
;
return
-
1
;
pa
+=
k
;
sortslice_advance
(
&
ssa
,
k
)
;
na
-=
k
;
na
-=
k
;
if
(
na
==
0
)
if
(
na
==
0
)
return
0
;
return
0
;
...
@@ -1674,7 +1770,7 @@ merge_at(MergeState *ms, Py_ssize_t i)
...
@@ -1674,7 +1770,7 @@ merge_at(MergeState *ms, Py_ssize_t i)
/* Where does a end in b? Elements in b after that can be
/* Where does a end in b? Elements in b after that can be
* ignored (already in place).
* ignored (already in place).
*/
*/
nb
=
gallop_left
(
pa
[
na
-
1
],
pb
,
nb
,
nb
-
1
);
nb
=
gallop_left
(
ssa
.
keys
[
na
-
1
],
ssb
.
keys
,
nb
,
nb
-
1
);
if
(
nb
<=
0
)
if
(
nb
<=
0
)
return
nb
;
return
nb
;
...
@@ -1682,9 +1778,9 @@ merge_at(MergeState *ms, Py_ssize_t i)
...
@@ -1682,9 +1778,9 @@ merge_at(MergeState *ms, Py_ssize_t i)
* min(na, nb) elements.
* min(na, nb) elements.
*/
*/
if
(
na
<=
nb
)
if
(
na
<=
nb
)
return
merge_lo
(
ms
,
pa
,
na
,
p
b
,
nb
);
return
merge_lo
(
ms
,
ssa
,
na
,
ss
b
,
nb
);
else
else
return
merge_hi
(
ms
,
pa
,
na
,
p
b
,
nb
);
return
merge_hi
(
ms
,
ssa
,
na
,
ss
b
,
nb
);
}
}
/* Examine the stack of runs waiting to be merged, merging adjacent runs
/* Examine the stack of runs waiting to be merged, merging adjacent runs
...
@@ -1765,103 +1861,12 @@ merge_compute_minrun(Py_ssize_t n)
...
@@ -1765,103 +1861,12 @@ merge_compute_minrun(Py_ssize_t n)
return
n
+
r
;
return
n
+
r
;
}
}
/* Special wrapper to support stable sorting using the decorate-sort-undecorate
pattern. Holds a key which is used for comparisons and the original record
which is returned during the undecorate phase. By exposing only the key
during comparisons, the underlying sort stability characteristics are left
unchanged. Also, the comparison function will only see the key instead of
a full record. */
typedef
struct
{
PyObject_HEAD
PyObject
*
key
;
PyObject
*
value
;
}
sortwrapperobject
;
PyDoc_STRVAR
(
sortwrapper_doc
,
"Object wrapper with a custom sort key."
);
static
PyObject
*
sortwrapper_richcompare
(
sortwrapperobject
*
,
sortwrapperobject
*
,
int
);
static
void
sortwrapper_dealloc
(
sortwrapperobject
*
);
PyTypeObject
PySortWrapper_Type
=
{
PyVarObject_HEAD_INIT
(
&
PyType_Type
,
0
)
"sortwrapper"
,
/* tp_name */
sizeof
(
sortwrapperobject
),
/* tp_basicsize */
0
,
/* tp_itemsize */
/* methods */
(
destructor
)
sortwrapper_dealloc
,
/* tp_dealloc */
0
,
/* tp_print */
0
,
/* tp_getattr */
0
,
/* tp_setattr */
0
,
/* tp_reserved */
0
,
/* tp_repr */
0
,
/* tp_as_number */
0
,
/* tp_as_sequence */
0
,
/* tp_as_mapping */
0
,
/* tp_hash */
0
,
/* tp_call */
0
,
/* tp_str */
PyObject_GenericGetAttr
,
/* tp_getattro */
0
,
/* tp_setattro */
0
,
/* tp_as_buffer */
Py_TPFLAGS_DEFAULT
,
/* tp_flags */
sortwrapper_doc
,
/* tp_doc */
0
,
/* tp_traverse */
0
,
/* tp_clear */
(
richcmpfunc
)
sortwrapper_richcompare
,
/* tp_richcompare */
};
static
PyObject
*
sortwrapper_richcompare
(
sortwrapperobject
*
a
,
sortwrapperobject
*
b
,
int
op
)
{
if
(
!
PyObject_TypeCheck
(
b
,
&
PySortWrapper_Type
))
{
PyErr_SetString
(
PyExc_TypeError
,
"expected a sortwrapperobject"
);
return
NULL
;
}
return
PyObject_RichCompare
(
a
->
key
,
b
->
key
,
op
);
}
static
void
static
void
sortwrapper_dealloc
(
sortwrapperobject
*
so
)
reverse_sortslice
(
sortslice
*
s
,
Py_ssize_t
n
)
{
Py_XDECREF
(
so
->
key
);
Py_XDECREF
(
so
->
value
);
PyObject_Del
(
so
);
}
/* Returns a new reference to a sortwrapper.
Consumes the references to the two underlying objects. */
static
PyObject
*
build_sortwrapper
(
PyObject
*
key
,
PyObject
*
value
)
{
{
sortwrapperobject
*
so
;
reverse_slice
(
s
->
keys
,
&
s
->
keys
[
n
]);
if
(
s
->
values
!=
NULL
)
so
=
PyObject_New
(
sortwrapperobject
,
&
PySortWrapper_Type
);
reverse_slice
(
s
->
values
,
&
s
->
values
[
n
]);
if
(
so
==
NULL
)
return
NULL
;
so
->
key
=
key
;
so
->
value
=
value
;
return
(
PyObject
*
)
so
;
}
/* Returns a new reference to the value underlying the wrapper. */
static
PyObject
*
sortwrapper_getvalue
(
PyObject
*
so
)
{
PyObject
*
value
;
if
(
!
PyObject_TypeCheck
(
so
,
&
PySortWrapper_Type
))
{
PyErr_SetString
(
PyExc_TypeError
,
"expected a sortwrapperobject"
);
return
NULL
;
}
value
=
((
sortwrapperobject
*
)
so
)
->
value
;
Py_INCREF
(
value
);
return
value
;
}
}
/* An adaptive, stable, natural mergesort. See listsort.txt.
/* An adaptive, stable, natural mergesort. See listsort.txt.
...
@@ -1873,9 +1878,9 @@ static PyObject *
...
@@ -1873,9 +1878,9 @@ static PyObject *
listsort
(
PyListObject
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
listsort
(
PyListObject
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
{
{
MergeState
ms
;
MergeState
ms
;
PyObject
**
lo
,
**
hi
;
Py_ssize_t
nremaining
;
Py_ssize_t
nremaining
;
Py_ssize_t
minrun
;
Py_ssize_t
minrun
;
sortslice
lo
;
Py_ssize_t
saved_ob_size
,
saved_allocated
;
Py_ssize_t
saved_ob_size
,
saved_allocated
;
PyObject
**
saved_ob_item
;
PyObject
**
saved_ob_item
;
PyObject
**
final_ob_item
;
PyObject
**
final_ob_item
;
...
@@ -1883,8 +1888,8 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds)
...
@@ -1883,8 +1888,8 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds)
int
reverse
=
0
;
int
reverse
=
0
;
PyObject
*
keyfunc
=
NULL
;
PyObject
*
keyfunc
=
NULL
;
Py_ssize_t
i
;
Py_ssize_t
i
;
PyObject
*
key
,
*
value
,
*
kvpair
;
static
char
*
kwlist
[]
=
{
"key"
,
"reverse"
,
0
};
static
char
*
kwlist
[]
=
{
"key"
,
"reverse"
,
0
};
PyObject
**
keys
;
assert
(
self
!=
NULL
);
assert
(
self
!=
NULL
);
assert
(
PyList_Check
(
self
));
assert
(
PyList_Check
(
self
));
...
@@ -1913,28 +1918,36 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds)
...
@@ -1913,28 +1918,36 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds)
self
->
ob_item
=
NULL
;
self
->
ob_item
=
NULL
;
self
->
allocated
=
-
1
;
/* any operation will reset it to >= 0 */
self
->
allocated
=
-
1
;
/* any operation will reset it to >= 0 */
if
(
keyfunc
!=
NULL
)
{
if
(
keyfunc
==
NULL
)
{
for
(
i
=
0
;
i
<
saved_ob_size
;
i
++
)
{
keys
=
NULL
;
value
=
saved_ob_item
[
i
];
lo
.
keys
=
saved_ob_item
;
key
=
PyObject_CallFunctionObjArgs
(
keyfunc
,
value
,
lo
.
values
=
NULL
;
NULL
);
}
if
(
key
==
NULL
)
{
else
{
for
(
i
=
i
-
1
;
i
>=
0
;
i
--
)
{
if
(
saved_ob_size
<
MERGESTATE_TEMP_SIZE
/
2
)
kvpair
=
saved_ob_item
[
i
];
/* Leverage stack space we allocated but won't otherwise use */
value
=
sortwrapper_getvalue
(
kvpair
);
keys
=
&
ms
.
temparray
[
saved_ob_size
+
1
];
saved_ob_item
[
i
]
=
value
;
else
{
Py_DECREF
(
kvpair
);
keys
=
PyMem_MALLOC
(
sizeof
(
PyObject
*
)
*
saved_ob_size
);
}
if
(
keys
==
NULL
)
goto
dsu_fail
;
return
NULL
;
}
for
(
i
=
0
;
i
<
saved_ob_size
;
i
++
)
{
keys
[
i
]
=
PyObject_CallFunctionObjArgs
(
keyfunc
,
saved_ob_item
[
i
],
NULL
);
if
(
keys
[
i
]
==
NULL
)
{
for
(
i
=
i
-
1
;
i
>=
0
;
i
--
)
Py_DECREF
(
keys
[
i
]);
goto
keyfunc_fail
;
}
}
kvpair
=
build_sortwrapper
(
key
,
value
);
if
(
kvpair
==
NULL
)
goto
dsu_fail
;
saved_ob_item
[
i
]
=
kvpair
;
}
}
lo
.
keys
=
keys
;
lo
.
values
=
saved_ob_item
;
}
}
merge_init
(
&
ms
);
merge_init
(
&
ms
,
saved_ob_size
,
keys
!=
NULL
);
nremaining
=
saved_ob_size
;
nremaining
=
saved_ob_size
;
if
(
nremaining
<
2
)
if
(
nremaining
<
2
)
...
@@ -1942,30 +1955,31 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds)
...
@@ -1942,30 +1955,31 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds)
/* Reverse sort stability achieved by initially reversing the list,
/* Reverse sort stability achieved by initially reversing the list,
applying a stable forward sort, then reversing the final result. */
applying a stable forward sort, then reversing the final result. */
if
(
reverse
)
if
(
reverse
)
{
reverse_slice
(
saved_ob_item
,
saved_ob_item
+
saved_ob_size
);
if
(
keys
!=
NULL
)
reverse_slice
(
&
keys
[
0
],
&
keys
[
saved_ob_size
]);
reverse_slice
(
&
saved_ob_item
[
0
],
&
saved_ob_item
[
saved_ob_size
]);
}
/* March over the array once, left to right, finding natural runs,
/* March over the array once, left to right, finding natural runs,
* and extending short natural runs to minrun elements.
* and extending short natural runs to minrun elements.
*/
*/
lo
=
saved_ob_item
;
hi
=
lo
+
nremaining
;
minrun
=
merge_compute_minrun
(
nremaining
);
minrun
=
merge_compute_minrun
(
nremaining
);
do
{
do
{
int
descending
;
int
descending
;
Py_ssize_t
n
;
Py_ssize_t
n
;
/* Identify next run. */
/* Identify next run. */
n
=
count_run
(
lo
,
hi
,
&
descending
);
n
=
count_run
(
lo
.
keys
,
lo
.
keys
+
nremaining
,
&
descending
);
if
(
n
<
0
)
if
(
n
<
0
)
goto
fail
;
goto
fail
;
if
(
descending
)
if
(
descending
)
reverse_s
lice
(
lo
,
lo
+
n
);
reverse_s
ortslice
(
&
lo
,
n
);
/* If short, extend to min(minrun, nremaining). */
/* If short, extend to min(minrun, nremaining). */
if
(
n
<
minrun
)
{
if
(
n
<
minrun
)
{
const
Py_ssize_t
force
=
nremaining
<=
minrun
?
const
Py_ssize_t
force
=
nremaining
<=
minrun
?
nremaining
:
minrun
;
nremaining
:
minrun
;
if
(
binarysort
(
lo
,
lo
+
force
,
lo
+
n
)
<
0
)
if
(
binarysort
(
lo
,
lo
.
keys
+
force
,
lo
.
keys
+
n
)
<
0
)
goto
fail
;
goto
fail
;
n
=
force
;
n
=
force
;
}
}
...
@@ -1977,27 +1991,27 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds)
...
@@ -1977,27 +1991,27 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds)
if
(
merge_collapse
(
&
ms
)
<
0
)
if
(
merge_collapse
(
&
ms
)
<
0
)
goto
fail
;
goto
fail
;
/* Advance to find next run. */
/* Advance to find next run. */
lo
+=
n
;
sortslice_advance
(
&
lo
,
n
)
;
nremaining
-=
n
;
nremaining
-=
n
;
}
while
(
nremaining
);
}
while
(
nremaining
);
assert
(
lo
==
hi
);
if
(
merge_force_collapse
(
&
ms
)
<
0
)
if
(
merge_force_collapse
(
&
ms
)
<
0
)
goto
fail
;
goto
fail
;
assert
(
ms
.
n
==
1
);
assert
(
ms
.
n
==
1
);
assert
(
ms
.
pending
[
0
].
base
==
saved_ob_item
);
assert
(
keys
==
NULL
?
ms
.
pending
[
0
].
base
.
keys
==
saved_ob_item
:
ms
.
pending
[
0
].
base
.
keys
==
&
keys
[
0
]);
assert
(
ms
.
pending
[
0
].
len
==
saved_ob_size
);
assert
(
ms
.
pending
[
0
].
len
==
saved_ob_size
);
lo
=
ms
.
pending
[
0
].
base
;
succeed:
succeed:
result
=
Py_None
;
result
=
Py_None
;
fail:
fail:
if
(
keyfunc
!=
NULL
)
{
if
(
keys
!=
NULL
)
{
for
(
i
=
0
;
i
<
saved_ob_size
;
i
++
)
{
for
(
i
=
0
;
i
<
saved_ob_size
;
i
++
)
kvpair
=
saved_ob_item
[
i
];
Py_DECREF
(
keys
[
i
]);
value
=
sortwrapper_getvalue
(
kvpair
);
if
(
keys
!=
&
ms
.
temparray
[
saved_ob_size
+
1
])
saved_ob_item
[
i
]
=
value
;
PyMem_FREE
(
keys
);
Py_DECREF
(
kvpair
);
}
}
}
if
(
self
->
allocated
!=
-
1
&&
result
!=
NULL
)
{
if
(
self
->
allocated
!=
-
1
&&
result
!=
NULL
)
{
...
@@ -2013,7 +2027,7 @@ fail:
...
@@ -2013,7 +2027,7 @@ fail:
merge_freemem
(
&
ms
);
merge_freemem
(
&
ms
);
dsu
_fail:
keyfunc
_fail:
final_ob_item
=
self
->
ob_item
;
final_ob_item
=
self
->
ob_item
;
i
=
Py_SIZE
(
self
);
i
=
Py_SIZE
(
self
);
Py_SIZE
(
self
)
=
saved_ob_size
;
Py_SIZE
(
self
)
=
saved_ob_size
;
...
@@ -2862,4 +2876,3 @@ listreviter_len(listreviterobject *it)
...
@@ -2862,4 +2876,3 @@ listreviter_len(listreviterobject *it)
len
=
0
;
len
=
0
;
return
PyLong_FromSsize_t
(
len
);
return
PyLong_FromSsize_t
(
len
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment