Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit beb3101

Browse files
committed
Add a C API for sets and frozensets.
1 parent e2eca0b commit beb3101

5 files changed

Lines changed: 210 additions & 12 deletions

File tree

Doc/api/concrete.tex

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2897,3 +2897,128 @@ \subsection{DateTime Objects \label{datetime-objects}}
28972897
tuple suitable for passing to \code{datetime.date.fromtimestamp()}.
28982898
\versionadded{2.4}
28992899
\end{cfuncdesc}
2900+
2901+
2902+
\subsection{Set Objects \label{setObjects}}
2903+
\sectionauthor{Raymond D. Hettinger}{[email protected]}
2904+
2905+
\obindex{set}
2906+
\obindex{frozenset}
2907+
\versionadded{2.5}
2908+
2909+
This section details the public API for \class{set} and \class{frozenset}
2910+
objects. Any functionality not listed below is best accessed using the
2911+
abstract object API (including
2912+
\cfunction{PyObject_CallMethod()}, \cfunction{PyObject_RichCompareBool()},
2913+
\cfunction{PyObject_Hash()}, \cfunction{PyObject_Repr()},
2914+
\cfunction{PyObject_IsTrue()}, \cfunction{PyObject_Print()}, and
2915+
\cfunction{PyObject_GetIter()}).
2916+
2917+
\begin{ctypedesc}{PySetObject}
2918+
This subtype of \ctype{PyObject} is used to hold the internal data for
2919+
both \class{set} and \class{frozenset} objects. It is like a
2920+
\ctype{PyDictObject} in that it is a fixed size for small sets
2921+
(much like tuple storage) and will point to a separate, variable sized
2922+
block of memory for medium and large sized sets (much like list storage).
2923+
None of the fields of this structure should be considered public and
2924+
are subject to change. All access should be done through the
2925+
documented API.
2926+
2927+
\end{ctypedesc}
2928+
2929+
\begin{cvardesc}{PyTypeObject}{PySet_Type}
2930+
This is an instance of \ctype{PyTypeObject} representing the Python
2931+
\class{set} type.
2932+
\end{cvardesc}
2933+
2934+
\begin{cvardesc}{PyTypeObject}{PyFrozenSet_Type}
2935+
This is an instance of \ctype{PyTypeObject} representing the Python
2936+
\class{frozenset} type.
2937+
\end{cvardesc}
2938+
2939+
2940+
The following type check macros work on pointers to any Python object.
2941+
Likewise, the constructor functions work with any iterable Python object.
2942+
2943+
\begin{cfuncdesc}{int}{PyAnySet_Check}{PyObject *p}
2944+
Returns true if \var{p} is a \class{set} object, a \class{frozenset}
2945+
object, or an instance of a subtype.
2946+
\end{cfuncdesc}
2947+
2948+
\begin{cfuncdesc}{int}{PyAnySet_CheckExact}{PyObject *p}
2949+
Returns true if \var{p} is a \class{set} object or a \class{frozenset}
2950+
object but not an instance of a subtype.
2951+
\end{cfuncdesc}
2952+
2953+
\begin{cfuncdesc}{int}{PyFrozenSet_CheckExact}{PyObject *p}
2954+
Returns true if \var{p} is a \class{frozenset} object
2955+
but not an instance of a subtype.
2956+
\end{cfuncdesc}
2957+
2958+
\begin{cfuncdesc}{PyObject*}{PySet_New}{PyObject *iterable}
2959+
Returns a new \class{set} containing objects returned by the
2960+
\var{iterable}. The \var{iterable} may be \NULL{} to create a
2961+
new empty set. Returns the new set on success or \NULL{} on
2962+
failure.
2963+
\end{cfuncdesc}
2964+
2965+
\begin{cfuncdesc}{PyObject*}{PyFrozenSet_New}{PyObject *iterable}
2966+
Returns a new \class{frozenset} containing objects returned by the
2967+
\var{iterable}. The \var{iterable} may be \NULL{} to create a
2968+
new empty frozenset. Returns the new set on success or \NULL{} on
2969+
failure.
2970+
\end{cfuncdesc}
2971+
2972+
2973+
The following functions and macros are available for instances of
2974+
\class{set} or \class{frozenset} or instances of their subtypes.
2975+
2976+
\begin{cfuncdesc}{int}{PySet_Size}{PyObject *anyset}
2977+
Returns the length of a \class{set} or \class{frozenset} object.
2978+
Equivalent to \samp{len(\var{anyset})}. Raises a
2979+
\exception{PyExc_SystemError} if the argument is not a \class{set},
2980+
\class{frozenset}, or an instance of a subtype.
2981+
\bifuncindex{len}
2982+
\end{cfuncdesc}
2983+
2984+
\begin{cfuncdesc}{int}{PySet_GET_SIZE}{PyObject *anyset}
2985+
Macro form of \cfunction{PySet_Size()} without error checking.
2986+
\end{cfuncdesc}
2987+
2988+
\begin{cfuncdesc}{int}{PySet_Contains}{PyObject *anyset, PyObject *key}
2989+
Returns 1 if found, 0 if not found, and -1 if an error is
2990+
encountered. Unlike the Python \method{__contains__()} method, this
2991+
function does not automatically convert unhashable sets into temporary
2992+
frozensets. Raises a \exception{TypeError} if the key is unhashable.
2993+
\end{cfuncdesc}
2994+
2995+
\begin{cfuncdesc}{int}{PySet_Discard}{PyObject *anyset, PyObject *key}
2996+
Returns 1 if found and removed, 0 if not found (no action taken),
2997+
and -1 if an error is encountered. Does not raise \exception{KeyError}
2998+
for missing keys. Raises a \exception{TypeError} if the key is unhashable.
2999+
Unlike the Python \method{discard()} method, this function does
3000+
not automatically convert unhashable sets into temporary frozensets.
3001+
\end{cfuncdesc}
3002+
3003+
3004+
The following functions are available for instances of \class{set} or
3005+
its subtypes but not for instances of \class{frozenset} or its subtypes.
3006+
3007+
\begin{cfuncdesc}{int}{PySet_Add}{PyObject *set, PyObject *key}
3008+
Adds \var{key} to a \class{set} instance. Does not apply to
3009+
\class{frozenset} instances. Returns 0 on success or -1 on failure.
3010+
Raises a \exception{TypeError} if the key is unhashable.
3011+
Raises a \exception{MemoryError} if there is no room to grow.
3012+
Raises a \exception{SystemError} if \var{key} is an not an instance
3013+
of \class{set} or its subtype.
3014+
\end{cfuncdesc}
3015+
3016+
\begin{cfuncdesc}{PyObject*}{PySet_Pop}{PyObject *set}
3017+
Returns a new reference to an arbitrary object in the \var{set},
3018+
and removes the object from the \var{set}. Returns \NULL{} on
3019+
failure. Raises \exception{KeyError} if the set is empty.
3020+
Raises a \exception{SystemError} if \var{key} is an not an instance
3021+
of \class{set} or its subtype.
3022+
\end{cfuncdesc}
3023+
3024+

Include/setobject.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ PyAPI_DATA(PyTypeObject) PyFrozenSet_Type;
7474
PyType_IsSubtype((ob)->ob_type, &PySet_Type) || \
7575
PyType_IsSubtype((ob)->ob_type, &PyFrozenSet_Type))
7676

77+
PyAPI_FUNC(PyObject *) PySet_New(PyObject *);
78+
PyAPI_FUNC(PyObject *) PyFrozenSet_New(PyObject *);
79+
PyAPI_FUNC(int) PySet_Size(PyObject *anyset);
80+
#define PySet_GET_SIZE(so) (((PySetObject *)(so))->used)
81+
PyAPI_FUNC(int) PySet_Contains(PyObject *anyset, PyObject *key);
82+
PyAPI_FUNC(int) PySet_Discard(PyObject *anyset, PyObject *key);
83+
PyAPI_FUNC(int) PySet_Add(PyObject *set, PyObject *key);
84+
PyAPI_FUNC(PyObject *) PySet_Pop(PyObject *set);
85+
7786
#ifdef __cplusplus
7887
}
7988
#endif

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,8 @@ Build
439439
C API
440440
-----
441441

442+
- Added a C API for set and frozenset objects.
443+
442444
- Removed PyRange_New().
443445

444446

Objects/setobject.c

Lines changed: 72 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -843,7 +843,7 @@ frozenset_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
843843
return iterable;
844844
}
845845
result = make_new_set(type, iterable);
846-
if (result == NULL || set_len(result))
846+
if (result == NULL || PySet_GET_SIZE(result))
847847
return result;
848848
Py_DECREF(result);
849849
}
@@ -1052,7 +1052,7 @@ set_intersection(PySetObject *so, PyObject *other)
10521052
int pos = 0;
10531053
setentry *entry;
10541054

1055-
if (set_len(other) > set_len((PyObject *)so)) {
1055+
if (PySet_GET_SIZE(other) > PySet_GET_SIZE(so)) {
10561056
tmp = (PyObject *)so;
10571057
so = (PySetObject *)other;
10581058
other = tmp;
@@ -1381,7 +1381,7 @@ set_issubset(PySetObject *so, PyObject *other)
13811381
Py_DECREF(tmp);
13821382
return result;
13831383
}
1384-
if (set_len((PyObject *)so) > set_len(other))
1384+
if (PySet_GET_SIZE(so) > PySet_GET_SIZE(other))
13851385
Py_RETURN_FALSE;
13861386

13871387
while (set_next(so, &pos, &entry)) {
@@ -1426,11 +1426,11 @@ set_richcompare(PySetObject *v, PyObject *w, int op)
14261426
}
14271427
switch (op) {
14281428
case Py_EQ:
1429-
if (set_len((PyObject *)v) != set_len(w))
1429+
if (PySet_GET_SIZE(v) != PySet_GET_SIZE(w))
14301430
Py_RETURN_FALSE;
14311431
return set_issubset(v, w);
14321432
case Py_NE:
1433-
if (set_len((PyObject *)v) != set_len(w))
1433+
if (PySet_GET_SIZE(v) != PySet_GET_SIZE(w))
14341434
Py_RETURN_TRUE;
14351435
r1 = set_issubset(v, w);
14361436
assert (r1 != NULL);
@@ -1442,11 +1442,11 @@ set_richcompare(PySetObject *v, PyObject *w, int op)
14421442
case Py_GE:
14431443
return set_issuperset(v, w);
14441444
case Py_LT:
1445-
if (set_len((PyObject *)v) >= set_len(w))
1445+
if (PySet_GET_SIZE(v) >= PySet_GET_SIZE(w))
14461446
Py_RETURN_FALSE;
14471447
return set_issubset(v, w);
14481448
case Py_GT:
1449-
if (set_len((PyObject *)v) <= set_len(w))
1449+
if (PySet_GET_SIZE(v) <= PySet_GET_SIZE(w))
14501450
Py_RETURN_FALSE;
14511451
return set_issuperset(v, w);
14521452
}
@@ -1472,7 +1472,7 @@ frozenset_hash(PyObject *self)
14721472
if (so->hash != -1)
14731473
return so->hash;
14741474

1475-
hash *= set_len(self) + 1;
1475+
hash *= PySet_GET_SIZE(self) + 1;
14761476
while (set_next(so, &pos, &entry)) {
14771477
/* Work to increase the bit dispersion for closely spaced hash
14781478
values. The is important because some use cases have many
@@ -1918,3 +1918,67 @@ PyTypeObject PyFrozenSet_Type = {
19181918
frozenset_new, /* tp_new */
19191919
PyObject_GC_Del, /* tp_free */
19201920
};
1921+
1922+
1923+
/***** C API functions *************************************************/
1924+
1925+
PyObject *
1926+
PySet_New(PyObject *iterable)
1927+
{
1928+
return make_new_set(&PySet_Type, iterable);
1929+
}
1930+
1931+
PyObject *
1932+
PyFrozenSet_New(PyObject *iterable)
1933+
{
1934+
PyObject *args = NULL, *result;
1935+
1936+
if (iterable != NULL) {
1937+
args = PyTuple_Pack(1, iterable);
1938+
if (args == NULL)
1939+
return NULL;
1940+
}
1941+
result = frozenset_new(&PyFrozenSet_Type, args, NULL);
1942+
Py_DECREF(args);
1943+
return result;
1944+
}
1945+
1946+
int
1947+
PySet_Contains(PyObject *anyset, PyObject *key)
1948+
{
1949+
if (!PyAnySet_Check(anyset)) {
1950+
PyErr_BadInternalCall();
1951+
return -1;
1952+
}
1953+
return set_contains_key((PySetObject *)anyset, key);
1954+
}
1955+
1956+
int
1957+
PySet_Discard(PyObject *anyset, PyObject *key)
1958+
{
1959+
if (!PyAnySet_Check(anyset)) {
1960+
PyErr_BadInternalCall();
1961+
return -1;
1962+
}
1963+
return set_discard_key((PySetObject *)anyset, key);
1964+
}
1965+
1966+
int
1967+
PySet_Add(PyObject *set, PyObject *key)
1968+
{
1969+
if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) {
1970+
PyErr_BadInternalCall();
1971+
return -1;
1972+
}
1973+
return set_add_key((PySetObject *)set, key);
1974+
}
1975+
1976+
PyObject *
1977+
PySet_Pop(PyObject *set)
1978+
{
1979+
if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) {
1980+
PyErr_BadInternalCall();
1981+
return NULL;
1982+
}
1983+
return set_pop((PySetObject *)set);
1984+
}

Python/marshal.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -773,11 +773,9 @@ r_object(RFILE *p)
773773
if (v == NULL)
774774
return v;
775775
if (type == TYPE_SET)
776-
v3 = PyObject_CallFunctionObjArgs(
777-
(PyObject *)&PySet_Type, v, NULL);
776+
v3 = PySet_New(v);
778777
else
779-
v3 = PyObject_CallFunctionObjArgs(
780-
(PyObject *)&PyFrozenSet_Type, v, NULL);
778+
v3 = PyFrozenSet_New(v);
781779
Py_DECREF(v);
782780
return v3;
783781

0 commit comments

Comments
 (0)