Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
6b91a597
Commit
6b91a597
authored
Dec 20, 2017
by
Serhiy Storchaka
Committed by
GitHub
Dec 20, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bpo-32385: Clean up the C3 MRO algorithm implementation. (#4942)
Use tuples and raw arrays instead of lists.
parent
ca719ac4
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
64 additions
and
77 deletions
+64
-77
Objects/typeobject.c
Objects/typeobject.c
+64
-77
No files found.
Objects/typeobject.c
View file @
6b91a597
...
@@ -1564,12 +1564,13 @@ call_maybe(PyObject *obj, _Py_Identifier *name,
...
@@ -1564,12 +1564,13 @@ call_maybe(PyObject *obj, _Py_Identifier *name,
*/
*/
static
int
static
int
tail_contains
(
PyObject
*
list
,
int
whence
,
PyObject
*
o
)
{
tail_contains
(
PyObject
*
tuple
,
int
whence
,
PyObject
*
o
)
{
Py_ssize_t
j
,
size
;
Py_ssize_t
j
,
size
;
size
=
Py
List_GET_SIZE
(
list
);
size
=
Py
Tuple_GET_SIZE
(
tuple
);
for
(
j
=
whence
+
1
;
j
<
size
;
j
++
)
{
for
(
j
=
whence
+
1
;
j
<
size
;
j
++
)
{
if
(
Py
List_GET_ITEM
(
list
,
j
)
==
o
)
if
(
Py
Tuple_GET_ITEM
(
tuple
,
j
)
==
o
)
return
1
;
return
1
;
}
}
return
0
;
return
0
;
...
@@ -1593,17 +1594,17 @@ class_name(PyObject *cls)
...
@@ -1593,17 +1594,17 @@ class_name(PyObject *cls)
}
}
static
int
static
int
check_duplicates
(
PyObject
*
list
)
check_duplicates
(
PyObject
*
tuple
)
{
{
Py_ssize_t
i
,
j
,
n
;
Py_ssize_t
i
,
j
,
n
;
/* Let's use a quadratic time algorithm,
/* Let's use a quadratic time algorithm,
assuming that the bases
list
s is short.
assuming that the bases
tuple
s is short.
*/
*/
n
=
Py
List_GET_SIZE
(
list
);
n
=
Py
Tuple_GET_SIZE
(
tuple
);
for
(
i
=
0
;
i
<
n
;
i
++
)
{
for
(
i
=
0
;
i
<
n
;
i
++
)
{
PyObject
*
o
=
Py
List_GET_ITEM
(
list
,
i
);
PyObject
*
o
=
Py
Tuple_GET_ITEM
(
tuple
,
i
);
for
(
j
=
i
+
1
;
j
<
n
;
j
++
)
{
for
(
j
=
i
+
1
;
j
<
n
;
j
++
)
{
if
(
Py
List_GET_ITEM
(
list
,
j
)
==
o
)
{
if
(
Py
Tuple_GET_ITEM
(
tuple
,
j
)
==
o
)
{
o
=
class_name
(
o
);
o
=
class_name
(
o
);
if
(
o
!=
NULL
)
{
if
(
o
!=
NULL
)
{
PyErr_Format
(
PyExc_TypeError
,
PyErr_Format
(
PyExc_TypeError
,
...
@@ -1631,19 +1632,18 @@ check_duplicates(PyObject *list)
...
@@ -1631,19 +1632,18 @@ check_duplicates(PyObject *list)
*/
*/
static
void
static
void
set_mro_error
(
PyObject
*
to_merg
e
,
int
*
remain
)
set_mro_error
(
PyObject
*
*
to_merge
,
Py_ssize_t
to_merge_siz
e
,
int
*
remain
)
{
{
Py_ssize_t
i
,
n
,
off
,
to_merge_size
;
Py_ssize_t
i
,
n
,
off
;
char
buf
[
1000
];
char
buf
[
1000
];
PyObject
*
k
,
*
v
;
PyObject
*
k
,
*
v
;
PyObject
*
set
=
PyDict_New
();
PyObject
*
set
=
PyDict_New
();
if
(
!
set
)
return
;
if
(
!
set
)
return
;
to_merge_size
=
PyList_GET_SIZE
(
to_merge
);
for
(
i
=
0
;
i
<
to_merge_size
;
i
++
)
{
for
(
i
=
0
;
i
<
to_merge_size
;
i
++
)
{
PyObject
*
L
=
PyList_GET_ITEM
(
to_merge
,
i
)
;
PyObject
*
L
=
to_merge
[
i
]
;
if
(
remain
[
i
]
<
Py
List
_GET_SIZE
(
L
))
{
if
(
remain
[
i
]
<
Py
Tuple
_GET_SIZE
(
L
))
{
PyObject
*
c
=
Py
List
_GET_ITEM
(
L
,
remain
[
i
]);
PyObject
*
c
=
Py
Tuple
_GET_ITEM
(
L
,
remain
[
i
]);
if
(
PyDict_SetItem
(
set
,
c
,
Py_None
)
<
0
)
{
if
(
PyDict_SetItem
(
set
,
c
,
Py_None
)
<
0
)
{
Py_DECREF
(
set
);
Py_DECREF
(
set
);
return
;
return
;
...
@@ -1676,19 +1676,17 @@ consistent method resolution\norder (MRO) for bases");
...
@@ -1676,19 +1676,17 @@ consistent method resolution\norder (MRO) for bases");
}
}
static
int
static
int
pmerge
(
PyObject
*
acc
,
PyObject
*
to_merg
e
)
pmerge
(
PyObject
*
acc
,
PyObject
**
to_merge
,
Py_ssize_t
to_merge_siz
e
)
{
{
int
res
=
0
;
int
res
=
0
;
Py_ssize_t
i
,
j
,
to_merge_size
,
empty_cnt
;
Py_ssize_t
i
,
j
,
empty_cnt
;
int
*
remain
;
int
*
remain
;
to_merge_size
=
PyList_GET_SIZE
(
to_merge
);
/* remain stores an index into each sublist of to_merge.
/* remain stores an index into each sublist of to_merge.
remain[i] is the index of the next base in to_merge[i]
remain[i] is the index of the next base in to_merge[i]
that is not included in acc.
that is not included in acc.
*/
*/
remain
=
(
int
*
)
PyMem_MALLOC
(
SIZEOF_INT
*
to_merge_size
);
remain
=
PyMem_New
(
int
,
to_merge_size
);
if
(
remain
==
NULL
)
{
if
(
remain
==
NULL
)
{
PyErr_NoMemory
();
PyErr_NoMemory
();
return
-
1
;
return
-
1
;
...
@@ -1701,9 +1699,9 @@ pmerge(PyObject *acc, PyObject* to_merge)
...
@@ -1701,9 +1699,9 @@ pmerge(PyObject *acc, PyObject* to_merge)
for
(
i
=
0
;
i
<
to_merge_size
;
i
++
)
{
for
(
i
=
0
;
i
<
to_merge_size
;
i
++
)
{
PyObject
*
candidate
;
PyObject
*
candidate
;
PyObject
*
cur_
list
=
PyList_GET_ITEM
(
to_merge
,
i
)
;
PyObject
*
cur_
tuple
=
to_merge
[
i
]
;
if
(
remain
[
i
]
>=
Py
List_GET_SIZE
(
cur_list
))
{
if
(
remain
[
i
]
>=
Py
Tuple_GET_SIZE
(
cur_tuple
))
{
empty_cnt
++
;
empty_cnt
++
;
continue
;
continue
;
}
}
...
@@ -1715,9 +1713,9 @@ pmerge(PyObject *acc, PyObject* to_merge)
...
@@ -1715,9 +1713,9 @@ pmerge(PyObject *acc, PyObject* to_merge)
of the earliest direct superclass of the new class.
of the earliest direct superclass of the new class.
*/
*/
candidate
=
Py
List_GET_ITEM
(
cur_list
,
remain
[
i
]);
candidate
=
Py
Tuple_GET_ITEM
(
cur_tuple
,
remain
[
i
]);
for
(
j
=
0
;
j
<
to_merge_size
;
j
++
)
{
for
(
j
=
0
;
j
<
to_merge_size
;
j
++
)
{
PyObject
*
j_lst
=
PyList_GET_ITEM
(
to_merge
,
j
)
;
PyObject
*
j_lst
=
to_merge
[
j
]
;
if
(
tail_contains
(
j_lst
,
remain
[
j
],
candidate
))
if
(
tail_contains
(
j_lst
,
remain
[
j
],
candidate
))
goto
skip
;
/* continue outer loop */
goto
skip
;
/* continue outer loop */
}
}
...
@@ -1726,9 +1724,9 @@ pmerge(PyObject *acc, PyObject* to_merge)
...
@@ -1726,9 +1724,9 @@ pmerge(PyObject *acc, PyObject* to_merge)
goto
out
;
goto
out
;
for
(
j
=
0
;
j
<
to_merge_size
;
j
++
)
{
for
(
j
=
0
;
j
<
to_merge_size
;
j
++
)
{
PyObject
*
j_lst
=
PyList_GET_ITEM
(
to_merge
,
j
)
;
PyObject
*
j_lst
=
to_merge
[
j
]
;
if
(
remain
[
j
]
<
Py
List
_GET_SIZE
(
j_lst
)
&&
if
(
remain
[
j
]
<
Py
Tuple
_GET_SIZE
(
j_lst
)
&&
Py
List
_GET_ITEM
(
j_lst
,
remain
[
j
])
==
candidate
)
{
Py
Tuple
_GET_ITEM
(
j_lst
,
remain
[
j
])
==
candidate
)
{
remain
[
j
]
++
;
remain
[
j
]
++
;
}
}
}
}
...
@@ -1737,12 +1735,12 @@ pmerge(PyObject *acc, PyObject* to_merge)
...
@@ -1737,12 +1735,12 @@ pmerge(PyObject *acc, PyObject* to_merge)
}
}
if
(
empty_cnt
!=
to_merge_size
)
{
if
(
empty_cnt
!=
to_merge_size
)
{
set_mro_error
(
to_merge
,
remain
);
set_mro_error
(
to_merge
,
to_merge_size
,
remain
);
res
=
-
1
;
res
=
-
1
;
}
}
out:
out:
PyMem_
FREE
(
remain
);
PyMem_
Del
(
remain
);
return
res
;
return
res
;
}
}
...
@@ -1750,10 +1748,9 @@ pmerge(PyObject *acc, PyObject* to_merge)
...
@@ -1750,10 +1748,9 @@ pmerge(PyObject *acc, PyObject* to_merge)
static
PyObject
*
static
PyObject
*
mro_implementation
(
PyTypeObject
*
type
)
mro_implementation
(
PyTypeObject
*
type
)
{
{
PyObject
*
result
=
NULL
;
PyObject
*
result
;
PyObject
*
bases
;
PyObject
*
bases
;
PyObject
*
to_merge
,
*
bases_aslist
;
PyObject
**
to_merge
;
int
res
;
Py_ssize_t
i
,
n
;
Py_ssize_t
i
,
n
;
if
(
type
->
tp_dict
==
NULL
)
{
if
(
type
->
tp_dict
==
NULL
)
{
...
@@ -1762,21 +1759,25 @@ mro_implementation(PyTypeObject *type)
...
@@ -1762,21 +1759,25 @@ mro_implementation(PyTypeObject *type)
}
}
bases
=
type
->
tp_bases
;
bases
=
type
->
tp_bases
;
assert
(
PyTuple_Check
(
bases
));
n
=
PyTuple_GET_SIZE
(
bases
);
n
=
PyTuple_GET_SIZE
(
bases
);
if
(
n
==
1
)
{
for
(
i
=
0
;
i
<
n
;
i
++
)
{
/* Fast path: if there is a single base, constructing the MRO
PyTypeObject
*
base
=
(
PyTypeObject
*
)
PyTuple_GET_ITEM
(
bases
,
i
);
* is trivial.
*/
PyTypeObject
*
base
=
(
PyTypeObject
*
)
PyTuple_GET_ITEM
(
bases
,
0
);
Py_ssize_t
k
;
if
(
base
->
tp_mro
==
NULL
)
{
if
(
base
->
tp_mro
==
NULL
)
{
PyErr_Format
(
PyExc_TypeError
,
PyErr_Format
(
PyExc_TypeError
,
"Cannot extend an incomplete type '%.100s'"
,
"Cannot extend an incomplete type '%.100s'"
,
base
->
tp_name
);
base
->
tp_name
);
return
NULL
;
return
NULL
;
}
}
k
=
PyTuple_GET_SIZE
(
base
->
tp_mro
);
assert
(
PyTuple_Check
(
base
->
tp_mro
));
}
if
(
n
==
1
)
{
/* Fast path: if there is a single base, constructing the MRO
* is trivial.
*/
PyTypeObject
*
base
=
(
PyTypeObject
*
)
PyTuple_GET_ITEM
(
bases
,
0
);
Py_ssize_t
k
=
PyTuple_GET_SIZE
(
base
->
tp_mro
);
result
=
PyTuple_New
(
k
+
1
);
result
=
PyTuple_New
(
k
+
1
);
if
(
result
==
NULL
)
{
if
(
result
==
NULL
)
{
return
NULL
;
return
NULL
;
...
@@ -1791,59 +1792,45 @@ mro_implementation(PyTypeObject *type)
...
@@ -1791,59 +1792,45 @@ mro_implementation(PyTypeObject *type)
return
result
;
return
result
;
}
}
/* This is just a basic sanity check. */
if
(
check_duplicates
(
bases
)
<
0
)
{
return
NULL
;
}
/* Find a superclass linearization that honors the constraints
/* Find a superclass linearization that honors the constraints
of the explicit
list
s of bases and the constraints implied by
of the explicit
tuple
s of bases and the constraints implied by
each base class.
each base class.
to_merge is a
list of lists, where each list
is a superclass
to_merge is a
n array of tuples, where each tuple
is a superclass
linearization implied by a base class. The last element of
linearization implied by a base class. The last element of
to_merge is the declared
list
of bases.
to_merge is the declared
tuple
of bases.
*/
*/
to_merge
=
PyList_New
(
n
+
1
);
to_merge
=
PyMem_New
(
PyObject
*
,
n
+
1
);
if
(
to_merge
==
NULL
)
if
(
to_merge
==
NULL
)
{
PyErr_NoMemory
();
return
NULL
;
return
NULL
;
for
(
i
=
0
;
i
<
n
;
i
++
)
{
PyTypeObject
*
base
;
PyObject
*
base_mro_aslist
;
base
=
(
PyTypeObject
*
)
PyTuple_GET_ITEM
(
bases
,
i
);
if
(
base
->
tp_mro
==
NULL
)
{
PyErr_Format
(
PyExc_TypeError
,
"Cannot extend an incomplete type '%.100s'"
,
base
->
tp_name
);
goto
out
;
}
}
base_mro_aslist
=
PySequence_List
(
base
->
tp_mro
);
for
(
i
=
0
;
i
<
n
;
i
++
)
{
if
(
base_mro_aslist
==
NULL
)
PyTypeObject
*
base
=
(
PyTypeObject
*
)
PyTuple_GET_ITEM
(
bases
,
i
);
goto
out
;
to_merge
[
i
]
=
base
->
tp_mro
;
PyList_SET_ITEM
(
to_merge
,
i
,
base_mro_aslist
);
}
}
to_merge
[
n
]
=
bases
;
bases_aslist
=
PySequence_List
(
bases
);
result
=
PyList_New
(
1
);
if
(
bases_aslist
==
NULL
)
if
(
result
==
NULL
)
{
goto
out
;
PyMem_Del
(
to_merge
);
/* This is just a basic sanity check. */
return
NULL
;
if
(
check_duplicates
(
bases_aslist
)
<
0
)
{
Py_DECREF
(
bases_aslist
);
goto
out
;
}
}
PyList_SET_ITEM
(
to_merge
,
n
,
bases_aslist
);
result
=
Py_BuildValue
(
"[O]"
,
(
PyObject
*
)
type
);
if
(
result
==
NULL
)
goto
out
;
res
=
pmerge
(
result
,
to_merge
);
Py_INCREF
(
type
);
if
(
res
<
0
)
PyList_SET_ITEM
(
result
,
0
,
(
PyObject
*
)
type
);
if
(
pmerge
(
result
,
to_merge
,
n
+
1
)
<
0
)
{
Py_CLEAR
(
result
);
Py_CLEAR
(
result
);
}
out:
PyMem_Del
(
to_merge
);
Py_DECREF
(
to_merge
);
return
result
;
return
result
;
}
}
...
...
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