Skip to content

Commit 034b90f

Browse files
committed
gh-112026: Restore removed private C API
Restore removed private C API functions, macros and structures which have no simple replacement for now: * _PyDict_GetItem_KnownHash() * _PyDict_NewPresized() * _PyHASH_BITS * _PyHASH_IMAG * _PyHASH_INF * _PyHASH_MODULUS * _PyHASH_MULTIPLIER * _PyLong_Copy() * _PyLong_FromDigits() * _PyLong_New() * _PyLong_Sign() * _PyObject_CallMethodId() * _PyObject_CallMethodNoArgs() * _PyObject_CallMethodOneArg() * _PyObject_CallOneArg() * _PyObject_EXTRA_INIT * _PyObject_FastCallDict() * _PyObject_GetAttrId() * _PyObject_Vectorcall() * _PyObject_VectorcallMethod() * _PyStack_AsDict() * _PyThread_CurrentFrames() * _PyUnicodeWriter structure * _PyUnicodeWriter_Dealloc() * _PyUnicodeWriter_Finish() * _PyUnicodeWriter_Init() * _PyUnicodeWriter_Prepare() * _PyUnicodeWriter_PrepareKind() * _PyUnicodeWriter_WriteASCIIString() * _PyUnicodeWriter_WriteChar() * _PyUnicodeWriter_WriteLatin1String() * _PyUnicodeWriter_WriteStr() * _PyUnicodeWriter_WriteSubstring() * _PyUnicode_AsString() * _PyUnicode_FromId() * _PyVectorcall_Function() * _Py_IDENTIFIER() * _Py_c_abs() * _Py_c_diff() * _Py_c_neg() * _Py_c_pow() * _Py_c_prod() * _Py_c_quot() * _Py_c_sum() * _Py_static_string() * _Py_static_string_init()
1 parent 422c0f0 commit 034b90f

20 files changed

+311
-230
lines changed

Include/cpython/abstract.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,28 @@
22
# error "this header file must not be included directly"
33
#endif
44

5+
/* === Object Protocol ================================================== */
6+
7+
/* Like PyObject_CallMethod(), but expect a _Py_Identifier*
8+
as the method name. */
9+
PyAPI_FUNC(PyObject*) _PyObject_CallMethodId(
10+
PyObject *obj,
11+
_Py_Identifier *name,
12+
const char *format, ...);
13+
14+
/* Convert keyword arguments from the FASTCALL (stack: C array, kwnames: tuple)
15+
format to a Python dictionary ("kwargs" dict).
16+
17+
The type of kwnames keys is not checked. The final function getting
18+
arguments is responsible to check if all keys are strings, for example using
19+
PyArg_ParseTupleAndKeywords() or PyArg_ValidateKeywordArguments().
20+
21+
Duplicate keys are merged using the last value. If duplicate keys must raise
22+
an exception, the caller is responsible to implement an explicit keys on
23+
kwnames. */
24+
PyAPI_FUNC(PyObject*) _PyStack_AsDict(PyObject *const *values, PyObject *kwnames);
25+
26+
527
/* === Vectorcall protocol (PEP 590) ============================= */
628

729
// PyVectorcall_NARGS() is exported as a function for the stable ABI.
@@ -16,6 +38,16 @@ _PyVectorcall_NARGS(size_t n)
1638

1739
PyAPI_FUNC(vectorcallfunc) PyVectorcall_Function(PyObject *callable);
1840

41+
// Backwards compatibility aliases (PEP 590) for API that was provisional
42+
// in Python 3.8
43+
#define _PyObject_Vectorcall PyObject_Vectorcall
44+
#define _PyObject_VectorcallMethod PyObject_VectorcallMethod
45+
#define _PyObject_FastCallDict PyObject_VectorcallDict
46+
#define _PyVectorcall_Function PyVectorcall_Function
47+
#define _PyObject_CallOneArg PyObject_CallOneArg
48+
#define _PyObject_CallMethodNoArgs PyObject_CallMethodNoArgs
49+
#define _PyObject_CallMethodOneArg PyObject_CallMethodOneArg
50+
1951
/* Same as PyObject_Vectorcall except that keyword arguments are passed as
2052
dict, which may be NULL if there are no keyword arguments. */
2153
PyAPI_FUNC(PyObject *) PyObject_VectorcallDict(

Include/cpython/complexobject.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ typedef struct {
77
double imag;
88
} Py_complex;
99

10+
// Operations on complex numbers.
11+
PyAPI_FUNC(Py_complex) _Py_c_sum(Py_complex, Py_complex);
12+
PyAPI_FUNC(Py_complex) _Py_c_diff(Py_complex, Py_complex);
13+
PyAPI_FUNC(Py_complex) _Py_c_neg(Py_complex);
14+
PyAPI_FUNC(Py_complex) _Py_c_prod(Py_complex, Py_complex);
15+
PyAPI_FUNC(Py_complex) _Py_c_quot(Py_complex, Py_complex);
16+
PyAPI_FUNC(Py_complex) _Py_c_pow(Py_complex, Py_complex);
17+
PyAPI_FUNC(double) _Py_c_abs(Py_complex);
18+
19+
1020
/* Complex object interface */
1121

1222
/*

Include/cpython/dictobject.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ typedef struct {
3232
PyDictValues *ma_values;
3333
} PyDictObject;
3434

35+
PyAPI_FUNC(PyObject *) _PyDict_GetItem_KnownHash(PyObject *mp, PyObject *key,
36+
Py_hash_t hash);
37+
3538
PyAPI_FUNC(PyObject *) PyDict_SetDefault(
3639
PyObject *mp, PyObject *key, PyObject *defaultobj);
3740

@@ -46,6 +49,8 @@ static inline Py_ssize_t PyDict_GET_SIZE(PyObject *op) {
4649

4750
PyAPI_FUNC(int) PyDict_ContainsString(PyObject *mp, const char *key);
4851

52+
PyAPI_FUNC(PyObject *) _PyDict_NewPresized(Py_ssize_t minused);
53+
4954
PyAPI_FUNC(int) PyDict_Pop(PyObject *dict, PyObject *key, PyObject **result);
5055
PyAPI_FUNC(int) PyDict_PopString(PyObject *dict, const char *key, PyObject **result);
5156
PyAPI_FUNC(PyObject *) _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *default_value);

Include/cpython/longintrepr.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,16 @@ struct _longobject {
8989
_PyLongValue long_value;
9090
};
9191

92+
PyAPI_FUNC(PyLongObject*) _PyLong_New(Py_ssize_t);
93+
94+
// Return a copy of src.
95+
PyAPI_FUNC(PyObject*) _PyLong_Copy(PyLongObject *src);
96+
97+
PyAPI_FUNC(PyLongObject*) _PyLong_FromDigits(
98+
int negative,
99+
Py_ssize_t digit_count,
100+
digit *digits);
101+
92102

93103
/* Inline some internals for speed. These should be in pycore_long.h
94104
* if user code didn't need them inlined. */

Include/cpython/longobject.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ PyAPI_FUNC(PyObject*) PyLong_FromUnicodeObject(PyObject *u, int base);
77
PyAPI_FUNC(int) PyUnstable_Long_IsCompact(const PyLongObject* op);
88
PyAPI_FUNC(Py_ssize_t) PyUnstable_Long_CompactValue(const PyLongObject* op);
99

10+
// _PyLong_Sign. Return 0 if v is 0, -1 if v < 0, +1 if v > 0.
11+
// v must not be NULL, and must be a normalized long.
12+
// There are no error cases.
13+
PyAPI_FUNC(int) _PyLong_Sign(PyObject *v);
14+
1015
/* _PyLong_FromByteArray: View the n unsigned bytes as a binary integer in
1116
base 256, and return a Python int with the same numeric value.
1217
If n is 0, the integer is 0. Else:

Include/cpython/object.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,44 @@ PyAPI_FUNC(Py_ssize_t) _PyInterpreterState_GetRefTotal(PyInterpreterState *);
1414
#endif
1515

1616

17+
/********************* String Literals ****************************************/
18+
/* This structure helps managing static strings. The basic usage goes like this:
19+
Instead of doing
20+
21+
r = PyObject_CallMethod(o, "foo", "args", ...);
22+
23+
do
24+
25+
_Py_IDENTIFIER(foo);
26+
...
27+
r = _PyObject_CallMethodId(o, &PyId_foo, "args", ...);
28+
29+
PyId_foo is a static variable, either on block level or file level. On first
30+
usage, the string "foo" is interned, and the structures are linked. On interpreter
31+
shutdown, all strings are released.
32+
33+
Alternatively, _Py_static_string allows choosing the variable name.
34+
_PyUnicode_FromId returns a borrowed reference to the interned string.
35+
_PyObject_{Get,Set,Has}AttrId are __getattr__ versions using _Py_Identifier*.
36+
*/
37+
typedef struct _Py_Identifier {
38+
const char* string;
39+
// Index in PyInterpreterState.unicode.ids.array. It is process-wide
40+
// unique and must be initialized to -1.
41+
Py_ssize_t index;
42+
} _Py_Identifier;
43+
44+
#ifndef Py_BUILD_CORE
45+
// For now we are keeping _Py_IDENTIFIER for continued use
46+
// in non-builtin extensions (and naughty PyPI modules).
47+
48+
#define _Py_static_string_init(value) { .string = (value), .index = -1 }
49+
#define _Py_static_string(varname, value) static _Py_Identifier varname = _Py_static_string_init(value)
50+
#define _Py_IDENTIFIER(varname) _Py_static_string(PyId_##varname, #varname)
51+
52+
#endif /* !Py_BUILD_CORE */
53+
54+
1755
typedef struct {
1856
/* Number implementations must check *both*
1957
arguments for proper type and implement the necessary conversions
@@ -238,6 +276,8 @@ PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
238276
PyAPI_FUNC(void) _Py_BreakPoint(void);
239277
PyAPI_FUNC(void) _PyObject_Dump(PyObject *);
240278

279+
PyAPI_FUNC(PyObject*) _PyObject_GetAttrId(PyObject *, _Py_Identifier *);
280+
241281
PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *);
242282
PyAPI_FUNC(void) PyObject_CallFinalizer(PyObject *);
243283
PyAPI_FUNC(int) PyObject_CallFinalizerFromDealloc(PyObject *);

Include/cpython/pyhash.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,24 @@
22
# error "this header file must not be included directly"
33
#endif
44

5+
/* Prime multiplier used in string and various other hashes. */
6+
#define _PyHASH_MULTIPLIER 1000003UL /* 0xf4243 */
7+
8+
/* Parameters used for the numeric hash implementation. See notes for
9+
_Py_HashDouble in Python/pyhash.c. Numeric hashes are based on
10+
reduction modulo the prime 2**_PyHASH_BITS - 1. */
11+
12+
#if SIZEOF_VOID_P >= 8
13+
# define _PyHASH_BITS 61
14+
#else
15+
# define _PyHASH_BITS 31
16+
#endif
17+
18+
#define _PyHASH_MODULUS (((size_t)1 << _PyHASH_BITS) - 1)
19+
#define _PyHASH_INF 314159
20+
#define _PyHASH_IMAG _PyHASH_MULTIPLIER
21+
22+
523
/* hash function definition */
624
typedef struct {
725
Py_hash_t (*const hash)(const void *, Py_ssize_t);

Include/cpython/pystate.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,11 @@ PyAPI_FUNC(void) PyThreadState_LeaveTracing(PyThreadState *tstate);
247247
The function returns 1 if _PyGILState_check_enabled is non-zero. */
248248
PyAPI_FUNC(int) PyGILState_Check(void);
249249

250+
/* The implementation of sys._current_frames() Returns a dict mapping
251+
thread id to that thread's current frame.
252+
*/
253+
PyAPI_FUNC(PyObject*) _PyThread_CurrentFrames(void);
254+
250255
/* Routines for advanced debuggers, requested by David Beazley.
251256
Don't use unless you know what you are doing! */
252257
PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_Main(void);

Include/cpython/unicodeobject.h

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
Py_DEPRECATED(3.13) typedef wchar_t PY_UNICODE_TYPE;
1010
Py_DEPRECATED(3.13) typedef wchar_t Py_UNICODE;
1111

12+
1213
/* --- Internal Unicode Operations ---------------------------------------- */
1314

1415
// Static inline functions to work with surrogates
@@ -43,6 +44,7 @@ static inline Py_UCS4 Py_UNICODE_LOW_SURROGATE(Py_UCS4 ch) {
4344
return (0xDC00 + (ch & 0x3FF));
4445
}
4546

47+
4648
/* --- Unicode Type ------------------------------------------------------- */
4749

4850
/* ASCII-only strings created through PyUnicode_New use the PyASCIIObject
@@ -375,6 +377,7 @@ static inline Py_UCS4 PyUnicode_MAX_CHAR_VALUE(PyObject *op)
375377
#define PyUnicode_MAX_CHAR_VALUE(op) \
376378
PyUnicode_MAX_CHAR_VALUE(_PyObject_CAST(op))
377379

380+
378381
/* === Public API ========================================================= */
379382

380383
/* With PEP 393, this is the recommended way to allocate a new unicode object.
@@ -440,6 +443,123 @@ PyAPI_FUNC(PyObject*) PyUnicode_FromKindAndData(
440443
const void *buffer,
441444
Py_ssize_t size);
442445

446+
447+
/* --- _PyUnicodeWriter API ----------------------------------------------- */
448+
449+
typedef struct {
450+
PyObject *buffer;
451+
void *data;
452+
int kind;
453+
Py_UCS4 maxchar;
454+
Py_ssize_t size;
455+
Py_ssize_t pos;
456+
457+
/* minimum number of allocated characters (default: 0) */
458+
Py_ssize_t min_length;
459+
460+
/* minimum character (default: 127, ASCII) */
461+
Py_UCS4 min_char;
462+
463+
/* If non-zero, overallocate the buffer (default: 0). */
464+
unsigned char overallocate;
465+
466+
/* If readonly is 1, buffer is a shared string (cannot be modified)
467+
and size is set to 0. */
468+
unsigned char readonly;
469+
} _PyUnicodeWriter ;
470+
471+
// Initialize a Unicode writer.
472+
//
473+
// By default, the minimum buffer size is 0 character and overallocation is
474+
// disabled. Set min_length, min_char and overallocate attributes to control
475+
// the allocation of the buffer.
476+
PyAPI_FUNC(void)
477+
_PyUnicodeWriter_Init(_PyUnicodeWriter *writer);
478+
479+
/* Prepare the buffer to write 'length' characters
480+
with the specified maximum character.
481+
482+
Return 0 on success, raise an exception and return -1 on error. */
483+
#define _PyUnicodeWriter_Prepare(WRITER, LENGTH, MAXCHAR) \
484+
(((MAXCHAR) <= (WRITER)->maxchar \
485+
&& (LENGTH) <= (WRITER)->size - (WRITER)->pos) \
486+
? 0 \
487+
: (((LENGTH) == 0) \
488+
? 0 \
489+
: _PyUnicodeWriter_PrepareInternal((WRITER), (LENGTH), (MAXCHAR))))
490+
491+
/* Don't call this function directly, use the _PyUnicodeWriter_Prepare() macro
492+
instead. */
493+
PyAPI_FUNC(int)
494+
_PyUnicodeWriter_PrepareInternal(_PyUnicodeWriter *writer,
495+
Py_ssize_t length, Py_UCS4 maxchar);
496+
497+
/* Prepare the buffer to have at least the kind KIND.
498+
For example, kind=PyUnicode_2BYTE_KIND ensures that the writer will
499+
support characters in range U+000-U+FFFF.
500+
501+
Return 0 on success, raise an exception and return -1 on error. */
502+
#define _PyUnicodeWriter_PrepareKind(WRITER, KIND) \
503+
((KIND) <= (WRITER)->kind \
504+
? 0 \
505+
: _PyUnicodeWriter_PrepareKindInternal((WRITER), (KIND)))
506+
507+
/* Don't call this function directly, use the _PyUnicodeWriter_PrepareKind()
508+
macro instead. */
509+
PyAPI_FUNC(int)
510+
_PyUnicodeWriter_PrepareKindInternal(_PyUnicodeWriter *writer,
511+
int kind);
512+
513+
/* Append a Unicode character.
514+
Return 0 on success, raise an exception and return -1 on error. */
515+
PyAPI_FUNC(int)
516+
_PyUnicodeWriter_WriteChar(_PyUnicodeWriter *writer,
517+
Py_UCS4 ch
518+
);
519+
520+
/* Append a Unicode string.
521+
Return 0 on success, raise an exception and return -1 on error. */
522+
PyAPI_FUNC(int)
523+
_PyUnicodeWriter_WriteStr(_PyUnicodeWriter *writer,
524+
PyObject *str /* Unicode string */
525+
);
526+
527+
/* Append a substring of a Unicode string.
528+
Return 0 on success, raise an exception and return -1 on error. */
529+
PyAPI_FUNC(int)
530+
_PyUnicodeWriter_WriteSubstring(_PyUnicodeWriter *writer,
531+
PyObject *str, /* Unicode string */
532+
Py_ssize_t start,
533+
Py_ssize_t end
534+
);
535+
536+
/* Append an ASCII-encoded byte string.
537+
Return 0 on success, raise an exception and return -1 on error. */
538+
PyAPI_FUNC(int)
539+
_PyUnicodeWriter_WriteASCIIString(_PyUnicodeWriter *writer,
540+
const char *str, /* ASCII-encoded byte string */
541+
Py_ssize_t len /* number of bytes, or -1 if unknown */
542+
);
543+
544+
/* Append a latin1-encoded byte string.
545+
Return 0 on success, raise an exception and return -1 on error. */
546+
PyAPI_FUNC(int)
547+
_PyUnicodeWriter_WriteLatin1String(_PyUnicodeWriter *writer,
548+
const char *str, /* latin1-encoded byte string */
549+
Py_ssize_t len /* length in bytes */
550+
);
551+
552+
/* Get the value of the writer as a Unicode string. Clear the
553+
buffer of the writer. Raise an exception and return NULL
554+
on error. */
555+
PyAPI_FUNC(PyObject *)
556+
_PyUnicodeWriter_Finish(_PyUnicodeWriter *writer);
557+
558+
/* Deallocate memory of a writer (clear its internal buffer). */
559+
PyAPI_FUNC(void)
560+
_PyUnicodeWriter_Dealloc(_PyUnicodeWriter *writer);
561+
562+
443563
/* --- Manage the default encoding ---------------------------------------- */
444564

445565
/* Returns a pointer to the default encoding (UTF-8) of the
@@ -457,6 +577,10 @@ PyAPI_FUNC(PyObject*) PyUnicode_FromKindAndData(
457577

458578
PyAPI_FUNC(const char *) PyUnicode_AsUTF8(PyObject *unicode);
459579

580+
// Alias kept for backward compatibility
581+
#define _PyUnicode_AsString PyUnicode_AsUTF8
582+
583+
460584
/* === Characters Type APIs =============================================== */
461585

462586
/* These should not be used directly. Use the Py_UNICODE_IS* and
@@ -570,3 +694,10 @@ static inline int Py_UNICODE_ISALNUM(Py_UCS4 ch) {
570694
|| Py_UNICODE_ISDIGIT(ch)
571695
|| Py_UNICODE_ISNUMERIC(ch));
572696
}
697+
698+
699+
/* === Misc functions ===================================================== */
700+
701+
// Return an interned Unicode object for an Identifier; may fail if there is no
702+
// memory.
703+
PyAPI_FUNC(PyObject*) _PyUnicode_FromId(_Py_Identifier*);

0 commit comments

Comments
 (0)