mirror of
https://github.com/python/cpython.git
synced 2025-09-27 18:59:43 +00:00
Add a C API for sets and frozensets.
This commit is contained in:
parent
e2eca0b709
commit
beb3101b05
5 changed files with 210 additions and 12 deletions
|
@ -2897,3 +2897,128 @@ Macros for the convenience of modules implementing the DB API:
|
||||||
tuple suitable for passing to \code{datetime.date.fromtimestamp()}.
|
tuple suitable for passing to \code{datetime.date.fromtimestamp()}.
|
||||||
\versionadded{2.4}
|
\versionadded{2.4}
|
||||||
\end{cfuncdesc}
|
\end{cfuncdesc}
|
||||||
|
|
||||||
|
|
||||||
|
\subsection{Set Objects \label{setObjects}}
|
||||||
|
\sectionauthor{Raymond D. Hettinger}{python@rcn.com}
|
||||||
|
|
||||||
|
\obindex{set}
|
||||||
|
\obindex{frozenset}
|
||||||
|
\versionadded{2.5}
|
||||||
|
|
||||||
|
This section details the public API for \class{set} and \class{frozenset}
|
||||||
|
objects. Any functionality not listed below is best accessed using the
|
||||||
|
abstract object API (including
|
||||||
|
\cfunction{PyObject_CallMethod()}, \cfunction{PyObject_RichCompareBool()},
|
||||||
|
\cfunction{PyObject_Hash()}, \cfunction{PyObject_Repr()},
|
||||||
|
\cfunction{PyObject_IsTrue()}, \cfunction{PyObject_Print()}, and
|
||||||
|
\cfunction{PyObject_GetIter()}).
|
||||||
|
|
||||||
|
\begin{ctypedesc}{PySetObject}
|
||||||
|
This subtype of \ctype{PyObject} is used to hold the internal data for
|
||||||
|
both \class{set} and \class{frozenset} objects. It is like a
|
||||||
|
\ctype{PyDictObject} in that it is a fixed size for small sets
|
||||||
|
(much like tuple storage) and will point to a separate, variable sized
|
||||||
|
block of memory for medium and large sized sets (much like list storage).
|
||||||
|
None of the fields of this structure should be considered public and
|
||||||
|
are subject to change. All access should be done through the
|
||||||
|
documented API.
|
||||||
|
|
||||||
|
\end{ctypedesc}
|
||||||
|
|
||||||
|
\begin{cvardesc}{PyTypeObject}{PySet_Type}
|
||||||
|
This is an instance of \ctype{PyTypeObject} representing the Python
|
||||||
|
\class{set} type.
|
||||||
|
\end{cvardesc}
|
||||||
|
|
||||||
|
\begin{cvardesc}{PyTypeObject}{PyFrozenSet_Type}
|
||||||
|
This is an instance of \ctype{PyTypeObject} representing the Python
|
||||||
|
\class{frozenset} type.
|
||||||
|
\end{cvardesc}
|
||||||
|
|
||||||
|
|
||||||
|
The following type check macros work on pointers to any Python object.
|
||||||
|
Likewise, the constructor functions work with any iterable Python object.
|
||||||
|
|
||||||
|
\begin{cfuncdesc}{int}{PyAnySet_Check}{PyObject *p}
|
||||||
|
Returns true if \var{p} is a \class{set} object, a \class{frozenset}
|
||||||
|
object, or an instance of a subtype.
|
||||||
|
\end{cfuncdesc}
|
||||||
|
|
||||||
|
\begin{cfuncdesc}{int}{PyAnySet_CheckExact}{PyObject *p}
|
||||||
|
Returns true if \var{p} is a \class{set} object or a \class{frozenset}
|
||||||
|
object but not an instance of a subtype.
|
||||||
|
\end{cfuncdesc}
|
||||||
|
|
||||||
|
\begin{cfuncdesc}{int}{PyFrozenSet_CheckExact}{PyObject *p}
|
||||||
|
Returns true if \var{p} is a \class{frozenset} object
|
||||||
|
but not an instance of a subtype.
|
||||||
|
\end{cfuncdesc}
|
||||||
|
|
||||||
|
\begin{cfuncdesc}{PyObject*}{PySet_New}{PyObject *iterable}
|
||||||
|
Returns a new \class{set} containing objects returned by the
|
||||||
|
\var{iterable}. The \var{iterable} may be \NULL{} to create a
|
||||||
|
new empty set. Returns the new set on success or \NULL{} on
|
||||||
|
failure.
|
||||||
|
\end{cfuncdesc}
|
||||||
|
|
||||||
|
\begin{cfuncdesc}{PyObject*}{PyFrozenSet_New}{PyObject *iterable}
|
||||||
|
Returns a new \class{frozenset} containing objects returned by the
|
||||||
|
\var{iterable}. The \var{iterable} may be \NULL{} to create a
|
||||||
|
new empty frozenset. Returns the new set on success or \NULL{} on
|
||||||
|
failure.
|
||||||
|
\end{cfuncdesc}
|
||||||
|
|
||||||
|
|
||||||
|
The following functions and macros are available for instances of
|
||||||
|
\class{set} or \class{frozenset} or instances of their subtypes.
|
||||||
|
|
||||||
|
\begin{cfuncdesc}{int}{PySet_Size}{PyObject *anyset}
|
||||||
|
Returns the length of a \class{set} or \class{frozenset} object.
|
||||||
|
Equivalent to \samp{len(\var{anyset})}. Raises a
|
||||||
|
\exception{PyExc_SystemError} if the argument is not a \class{set},
|
||||||
|
\class{frozenset}, or an instance of a subtype.
|
||||||
|
\bifuncindex{len}
|
||||||
|
\end{cfuncdesc}
|
||||||
|
|
||||||
|
\begin{cfuncdesc}{int}{PySet_GET_SIZE}{PyObject *anyset}
|
||||||
|
Macro form of \cfunction{PySet_Size()} without error checking.
|
||||||
|
\end{cfuncdesc}
|
||||||
|
|
||||||
|
\begin{cfuncdesc}{int}{PySet_Contains}{PyObject *anyset, PyObject *key}
|
||||||
|
Returns 1 if found, 0 if not found, and -1 if an error is
|
||||||
|
encountered. Unlike the Python \method{__contains__()} method, this
|
||||||
|
function does not automatically convert unhashable sets into temporary
|
||||||
|
frozensets. Raises a \exception{TypeError} if the key is unhashable.
|
||||||
|
\end{cfuncdesc}
|
||||||
|
|
||||||
|
\begin{cfuncdesc}{int}{PySet_Discard}{PyObject *anyset, PyObject *key}
|
||||||
|
Returns 1 if found and removed, 0 if not found (no action taken),
|
||||||
|
and -1 if an error is encountered. Does not raise \exception{KeyError}
|
||||||
|
for missing keys. Raises a \exception{TypeError} if the key is unhashable.
|
||||||
|
Unlike the Python \method{discard()} method, this function does
|
||||||
|
not automatically convert unhashable sets into temporary frozensets.
|
||||||
|
\end{cfuncdesc}
|
||||||
|
|
||||||
|
|
||||||
|
The following functions are available for instances of \class{set} or
|
||||||
|
its subtypes but not for instances of \class{frozenset} or its subtypes.
|
||||||
|
|
||||||
|
\begin{cfuncdesc}{int}{PySet_Add}{PyObject *set, PyObject *key}
|
||||||
|
Adds \var{key} to a \class{set} instance. Does not apply to
|
||||||
|
\class{frozenset} instances. Returns 0 on success or -1 on failure.
|
||||||
|
Raises a \exception{TypeError} if the key is unhashable.
|
||||||
|
Raises a \exception{MemoryError} if there is no room to grow.
|
||||||
|
Raises a \exception{SystemError} if \var{key} is an not an instance
|
||||||
|
of \class{set} or its subtype.
|
||||||
|
\end{cfuncdesc}
|
||||||
|
|
||||||
|
\begin{cfuncdesc}{PyObject*}{PySet_Pop}{PyObject *set}
|
||||||
|
Returns a new reference to an arbitrary object in the \var{set},
|
||||||
|
and removes the object from the \var{set}. Returns \NULL{} on
|
||||||
|
failure. Raises \exception{KeyError} if the set is empty.
|
||||||
|
Raises a \exception{SystemError} if \var{key} is an not an instance
|
||||||
|
of \class{set} or its subtype.
|
||||||
|
\end{cfuncdesc}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,15 @@ PyAPI_DATA(PyTypeObject) PyFrozenSet_Type;
|
||||||
PyType_IsSubtype((ob)->ob_type, &PySet_Type) || \
|
PyType_IsSubtype((ob)->ob_type, &PySet_Type) || \
|
||||||
PyType_IsSubtype((ob)->ob_type, &PyFrozenSet_Type))
|
PyType_IsSubtype((ob)->ob_type, &PyFrozenSet_Type))
|
||||||
|
|
||||||
|
PyAPI_FUNC(PyObject *) PySet_New(PyObject *);
|
||||||
|
PyAPI_FUNC(PyObject *) PyFrozenSet_New(PyObject *);
|
||||||
|
PyAPI_FUNC(int) PySet_Size(PyObject *anyset);
|
||||||
|
#define PySet_GET_SIZE(so) (((PySetObject *)(so))->used)
|
||||||
|
PyAPI_FUNC(int) PySet_Contains(PyObject *anyset, PyObject *key);
|
||||||
|
PyAPI_FUNC(int) PySet_Discard(PyObject *anyset, PyObject *key);
|
||||||
|
PyAPI_FUNC(int) PySet_Add(PyObject *set, PyObject *key);
|
||||||
|
PyAPI_FUNC(PyObject *) PySet_Pop(PyObject *set);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -439,6 +439,8 @@ Build
|
||||||
C API
|
C API
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
- Added a C API for set and frozenset objects.
|
||||||
|
|
||||||
- Removed PyRange_New().
|
- Removed PyRange_New().
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -843,7 +843,7 @@ frozenset_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
return iterable;
|
return iterable;
|
||||||
}
|
}
|
||||||
result = make_new_set(type, iterable);
|
result = make_new_set(type, iterable);
|
||||||
if (result == NULL || set_len(result))
|
if (result == NULL || PySet_GET_SIZE(result))
|
||||||
return result;
|
return result;
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
}
|
}
|
||||||
|
@ -1052,7 +1052,7 @@ set_intersection(PySetObject *so, PyObject *other)
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
setentry *entry;
|
setentry *entry;
|
||||||
|
|
||||||
if (set_len(other) > set_len((PyObject *)so)) {
|
if (PySet_GET_SIZE(other) > PySet_GET_SIZE(so)) {
|
||||||
tmp = (PyObject *)so;
|
tmp = (PyObject *)so;
|
||||||
so = (PySetObject *)other;
|
so = (PySetObject *)other;
|
||||||
other = tmp;
|
other = tmp;
|
||||||
|
@ -1381,7 +1381,7 @@ set_issubset(PySetObject *so, PyObject *other)
|
||||||
Py_DECREF(tmp);
|
Py_DECREF(tmp);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (set_len((PyObject *)so) > set_len(other))
|
if (PySet_GET_SIZE(so) > PySet_GET_SIZE(other))
|
||||||
Py_RETURN_FALSE;
|
Py_RETURN_FALSE;
|
||||||
|
|
||||||
while (set_next(so, &pos, &entry)) {
|
while (set_next(so, &pos, &entry)) {
|
||||||
|
@ -1426,11 +1426,11 @@ set_richcompare(PySetObject *v, PyObject *w, int op)
|
||||||
}
|
}
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Py_EQ:
|
case Py_EQ:
|
||||||
if (set_len((PyObject *)v) != set_len(w))
|
if (PySet_GET_SIZE(v) != PySet_GET_SIZE(w))
|
||||||
Py_RETURN_FALSE;
|
Py_RETURN_FALSE;
|
||||||
return set_issubset(v, w);
|
return set_issubset(v, w);
|
||||||
case Py_NE:
|
case Py_NE:
|
||||||
if (set_len((PyObject *)v) != set_len(w))
|
if (PySet_GET_SIZE(v) != PySet_GET_SIZE(w))
|
||||||
Py_RETURN_TRUE;
|
Py_RETURN_TRUE;
|
||||||
r1 = set_issubset(v, w);
|
r1 = set_issubset(v, w);
|
||||||
assert (r1 != NULL);
|
assert (r1 != NULL);
|
||||||
|
@ -1442,11 +1442,11 @@ set_richcompare(PySetObject *v, PyObject *w, int op)
|
||||||
case Py_GE:
|
case Py_GE:
|
||||||
return set_issuperset(v, w);
|
return set_issuperset(v, w);
|
||||||
case Py_LT:
|
case Py_LT:
|
||||||
if (set_len((PyObject *)v) >= set_len(w))
|
if (PySet_GET_SIZE(v) >= PySet_GET_SIZE(w))
|
||||||
Py_RETURN_FALSE;
|
Py_RETURN_FALSE;
|
||||||
return set_issubset(v, w);
|
return set_issubset(v, w);
|
||||||
case Py_GT:
|
case Py_GT:
|
||||||
if (set_len((PyObject *)v) <= set_len(w))
|
if (PySet_GET_SIZE(v) <= PySet_GET_SIZE(w))
|
||||||
Py_RETURN_FALSE;
|
Py_RETURN_FALSE;
|
||||||
return set_issuperset(v, w);
|
return set_issuperset(v, w);
|
||||||
}
|
}
|
||||||
|
@ -1472,7 +1472,7 @@ frozenset_hash(PyObject *self)
|
||||||
if (so->hash != -1)
|
if (so->hash != -1)
|
||||||
return so->hash;
|
return so->hash;
|
||||||
|
|
||||||
hash *= set_len(self) + 1;
|
hash *= PySet_GET_SIZE(self) + 1;
|
||||||
while (set_next(so, &pos, &entry)) {
|
while (set_next(so, &pos, &entry)) {
|
||||||
/* Work to increase the bit dispersion for closely spaced hash
|
/* Work to increase the bit dispersion for closely spaced hash
|
||||||
values. The is important because some use cases have many
|
values. The is important because some use cases have many
|
||||||
|
@ -1918,3 +1918,67 @@ PyTypeObject PyFrozenSet_Type = {
|
||||||
frozenset_new, /* tp_new */
|
frozenset_new, /* tp_new */
|
||||||
PyObject_GC_Del, /* tp_free */
|
PyObject_GC_Del, /* tp_free */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/***** C API functions *************************************************/
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PySet_New(PyObject *iterable)
|
||||||
|
{
|
||||||
|
return make_new_set(&PySet_Type, iterable);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyFrozenSet_New(PyObject *iterable)
|
||||||
|
{
|
||||||
|
PyObject *args = NULL, *result;
|
||||||
|
|
||||||
|
if (iterable != NULL) {
|
||||||
|
args = PyTuple_Pack(1, iterable);
|
||||||
|
if (args == NULL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
result = frozenset_new(&PyFrozenSet_Type, args, NULL);
|
||||||
|
Py_DECREF(args);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PySet_Contains(PyObject *anyset, PyObject *key)
|
||||||
|
{
|
||||||
|
if (!PyAnySet_Check(anyset)) {
|
||||||
|
PyErr_BadInternalCall();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return set_contains_key((PySetObject *)anyset, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PySet_Discard(PyObject *anyset, PyObject *key)
|
||||||
|
{
|
||||||
|
if (!PyAnySet_Check(anyset)) {
|
||||||
|
PyErr_BadInternalCall();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return set_discard_key((PySetObject *)anyset, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PySet_Add(PyObject *set, PyObject *key)
|
||||||
|
{
|
||||||
|
if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) {
|
||||||
|
PyErr_BadInternalCall();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return set_add_key((PySetObject *)set, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PySet_Pop(PyObject *set)
|
||||||
|
{
|
||||||
|
if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) {
|
||||||
|
PyErr_BadInternalCall();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return set_pop((PySetObject *)set);
|
||||||
|
}
|
||||||
|
|
|
@ -773,11 +773,9 @@ r_object(RFILE *p)
|
||||||
if (v == NULL)
|
if (v == NULL)
|
||||||
return v;
|
return v;
|
||||||
if (type == TYPE_SET)
|
if (type == TYPE_SET)
|
||||||
v3 = PyObject_CallFunctionObjArgs(
|
v3 = PySet_New(v);
|
||||||
(PyObject *)&PySet_Type, v, NULL);
|
|
||||||
else
|
else
|
||||||
v3 = PyObject_CallFunctionObjArgs(
|
v3 = PyFrozenSet_New(v);
|
||||||
(PyObject *)&PyFrozenSet_Type, v, NULL);
|
|
||||||
Py_DECREF(v);
|
Py_DECREF(v);
|
||||||
return v3;
|
return v3;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue