mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-22 21:32:31 +00:00
python-3.6.zip added from Github
README.cosmo contains the necessary links.
This commit is contained in:
parent
75fc601ff5
commit
0c4c56ff39
4219 changed files with 1968626 additions and 0 deletions
1
third_party/python/Objects/README
vendored
Normal file
1
third_party/python/Objects/README
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
Source files for various builtin objects
|
3246
third_party/python/Objects/abstract.c
vendored
Normal file
3246
third_party/python/Objects/abstract.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
115
third_party/python/Objects/accu.c
vendored
Normal file
115
third_party/python/Objects/accu.c
vendored
Normal file
|
@ -0,0 +1,115 @@
|
|||
/* Accumulator struct implementation */
|
||||
|
||||
#include "Python.h"
|
||||
#include "accu.h"
|
||||
|
||||
static PyObject *
|
||||
join_list_unicode(PyObject *lst)
|
||||
{
|
||||
/* return ''.join(lst) */
|
||||
PyObject *sep, *ret;
|
||||
sep = PyUnicode_FromStringAndSize("", 0);
|
||||
ret = PyUnicode_Join(sep, lst);
|
||||
Py_DECREF(sep);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
_PyAccu_Init(_PyAccu *acc)
|
||||
{
|
||||
/* Lazily allocated */
|
||||
acc->large = NULL;
|
||||
acc->small = PyList_New(0);
|
||||
if (acc->small == NULL)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
flush_accumulator(_PyAccu *acc)
|
||||
{
|
||||
Py_ssize_t nsmall = PyList_GET_SIZE(acc->small);
|
||||
if (nsmall) {
|
||||
int ret;
|
||||
PyObject *joined;
|
||||
if (acc->large == NULL) {
|
||||
acc->large = PyList_New(0);
|
||||
if (acc->large == NULL)
|
||||
return -1;
|
||||
}
|
||||
joined = join_list_unicode(acc->small);
|
||||
if (joined == NULL)
|
||||
return -1;
|
||||
if (PyList_SetSlice(acc->small, 0, nsmall, NULL)) {
|
||||
Py_DECREF(joined);
|
||||
return -1;
|
||||
}
|
||||
ret = PyList_Append(acc->large, joined);
|
||||
Py_DECREF(joined);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_PyAccu_Accumulate(_PyAccu *acc, PyObject *unicode)
|
||||
{
|
||||
Py_ssize_t nsmall;
|
||||
assert(PyUnicode_Check(unicode));
|
||||
|
||||
if (PyList_Append(acc->small, unicode))
|
||||
return -1;
|
||||
nsmall = PyList_GET_SIZE(acc->small);
|
||||
/* Each item in a list of unicode objects has an overhead (in 64-bit
|
||||
* builds) of:
|
||||
* - 8 bytes for the list slot
|
||||
* - 56 bytes for the header of the unicode object
|
||||
* that is, 64 bytes. 100000 such objects waste more than 6MB
|
||||
* compared to a single concatenated string.
|
||||
*/
|
||||
if (nsmall < 100000)
|
||||
return 0;
|
||||
return flush_accumulator(acc);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyAccu_FinishAsList(_PyAccu *acc)
|
||||
{
|
||||
int ret;
|
||||
PyObject *res;
|
||||
|
||||
ret = flush_accumulator(acc);
|
||||
Py_CLEAR(acc->small);
|
||||
if (ret) {
|
||||
Py_CLEAR(acc->large);
|
||||
return NULL;
|
||||
}
|
||||
res = acc->large;
|
||||
acc->large = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyAccu_Finish(_PyAccu *acc)
|
||||
{
|
||||
PyObject *list, *res;
|
||||
if (acc->large == NULL) {
|
||||
list = acc->small;
|
||||
acc->small = NULL;
|
||||
}
|
||||
else {
|
||||
list = _PyAccu_FinishAsList(acc);
|
||||
if (!list)
|
||||
return NULL;
|
||||
}
|
||||
res = join_list_unicode(list);
|
||||
Py_DECREF(list);
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
_PyAccu_Destroy(_PyAccu *acc)
|
||||
{
|
||||
Py_CLEAR(acc->small);
|
||||
Py_CLEAR(acc->large);
|
||||
}
|
184
third_party/python/Objects/boolobject.c
vendored
Normal file
184
third_party/python/Objects/boolobject.c
vendored
Normal file
|
@ -0,0 +1,184 @@
|
|||
/* Boolean type, a subtype of int */
|
||||
|
||||
#include "Python.h"
|
||||
#include "longintrepr.h"
|
||||
|
||||
/* We define bool_repr to return "False" or "True" */
|
||||
|
||||
static PyObject *false_str = NULL;
|
||||
static PyObject *true_str = NULL;
|
||||
|
||||
static PyObject *
|
||||
bool_repr(PyObject *self)
|
||||
{
|
||||
PyObject *s;
|
||||
|
||||
if (self == Py_True)
|
||||
s = true_str ? true_str :
|
||||
(true_str = PyUnicode_InternFromString("True"));
|
||||
else
|
||||
s = false_str ? false_str :
|
||||
(false_str = PyUnicode_InternFromString("False"));
|
||||
Py_XINCREF(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Function to return a bool from a C long */
|
||||
|
||||
PyObject *PyBool_FromLong(long ok)
|
||||
{
|
||||
PyObject *result;
|
||||
|
||||
if (ok)
|
||||
result = Py_True;
|
||||
else
|
||||
result = Py_False;
|
||||
Py_INCREF(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* We define bool_new to always return either Py_True or Py_False */
|
||||
|
||||
static PyObject *
|
||||
bool_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static char *kwlist[] = {"x", 0};
|
||||
PyObject *x = Py_False;
|
||||
long ok;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:bool", kwlist, &x))
|
||||
return NULL;
|
||||
ok = PyObject_IsTrue(x);
|
||||
if (ok < 0)
|
||||
return NULL;
|
||||
return PyBool_FromLong(ok);
|
||||
}
|
||||
|
||||
/* Arithmetic operations redefined to return bool if both args are bool. */
|
||||
|
||||
static PyObject *
|
||||
bool_and(PyObject *a, PyObject *b)
|
||||
{
|
||||
if (!PyBool_Check(a) || !PyBool_Check(b))
|
||||
return PyLong_Type.tp_as_number->nb_and(a, b);
|
||||
return PyBool_FromLong((a == Py_True) & (b == Py_True));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bool_or(PyObject *a, PyObject *b)
|
||||
{
|
||||
if (!PyBool_Check(a) || !PyBool_Check(b))
|
||||
return PyLong_Type.tp_as_number->nb_or(a, b);
|
||||
return PyBool_FromLong((a == Py_True) | (b == Py_True));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
bool_xor(PyObject *a, PyObject *b)
|
||||
{
|
||||
if (!PyBool_Check(a) || !PyBool_Check(b))
|
||||
return PyLong_Type.tp_as_number->nb_xor(a, b);
|
||||
return PyBool_FromLong((a == Py_True) ^ (b == Py_True));
|
||||
}
|
||||
|
||||
/* Doc string */
|
||||
|
||||
PyDoc_STRVAR(bool_doc,
|
||||
"bool(x) -> bool\n\
|
||||
\n\
|
||||
Returns True when the argument x is true, False otherwise.\n\
|
||||
The builtins True and False are the only two instances of the class bool.\n\
|
||||
The class bool is a subclass of the class int, and cannot be subclassed.");
|
||||
|
||||
/* Arithmetic methods -- only so we can override &, |, ^. */
|
||||
|
||||
static PyNumberMethods bool_as_number = {
|
||||
0, /* nb_add */
|
||||
0, /* nb_subtract */
|
||||
0, /* nb_multiply */
|
||||
0, /* nb_remainder */
|
||||
0, /* nb_divmod */
|
||||
0, /* nb_power */
|
||||
0, /* nb_negative */
|
||||
0, /* nb_positive */
|
||||
0, /* nb_absolute */
|
||||
0, /* nb_bool */
|
||||
0, /* nb_invert */
|
||||
0, /* nb_lshift */
|
||||
0, /* nb_rshift */
|
||||
bool_and, /* nb_and */
|
||||
bool_xor, /* nb_xor */
|
||||
bool_or, /* nb_or */
|
||||
0, /* nb_int */
|
||||
0, /* nb_reserved */
|
||||
0, /* nb_float */
|
||||
0, /* nb_inplace_add */
|
||||
0, /* nb_inplace_subtract */
|
||||
0, /* nb_inplace_multiply */
|
||||
0, /* nb_inplace_remainder */
|
||||
0, /* nb_inplace_power */
|
||||
0, /* nb_inplace_lshift */
|
||||
0, /* nb_inplace_rshift */
|
||||
0, /* nb_inplace_and */
|
||||
0, /* nb_inplace_xor */
|
||||
0, /* nb_inplace_or */
|
||||
0, /* nb_floor_divide */
|
||||
0, /* nb_true_divide */
|
||||
0, /* nb_inplace_floor_divide */
|
||||
0, /* nb_inplace_true_divide */
|
||||
0, /* nb_index */
|
||||
};
|
||||
|
||||
/* The type object for bool. Note that this cannot be subclassed! */
|
||||
|
||||
PyTypeObject PyBool_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"bool",
|
||||
sizeof(struct _longobject),
|
||||
0,
|
||||
0, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
bool_repr, /* tp_repr */
|
||||
&bool_as_number, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
bool_repr, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
bool_doc, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
&PyLong_Type, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
bool_new, /* tp_new */
|
||||
};
|
||||
|
||||
/* The objects representing bool values False and True */
|
||||
|
||||
struct _longobject _Py_FalseStruct = {
|
||||
PyVarObject_HEAD_INIT(&PyBool_Type, 0)
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
struct _longobject _Py_TrueStruct = {
|
||||
PyVarObject_HEAD_INIT(&PyBool_Type, 1)
|
||||
{ 1 }
|
||||
};
|
2437
third_party/python/Objects/bytearrayobject.c
vendored
Normal file
2437
third_party/python/Objects/bytearrayobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
821
third_party/python/Objects/bytes_methods.c
vendored
Normal file
821
third_party/python/Objects/bytes_methods.c
vendored
Normal file
|
@ -0,0 +1,821 @@
|
|||
#define PY_SSIZE_T_CLEAN
|
||||
#include "Python.h"
|
||||
#include "bytes_methods.h"
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_isspace__doc__,
|
||||
"B.isspace() -> bool\n\
|
||||
\n\
|
||||
Return True if all characters in B are whitespace\n\
|
||||
and there is at least one character in B, False otherwise.");
|
||||
|
||||
PyObject*
|
||||
_Py_bytes_isspace(const char *cptr, Py_ssize_t len)
|
||||
{
|
||||
const unsigned char *p
|
||||
= (unsigned char *) cptr;
|
||||
const unsigned char *e;
|
||||
|
||||
/* Shortcut for single character strings */
|
||||
if (len == 1 && Py_ISSPACE(*p))
|
||||
Py_RETURN_TRUE;
|
||||
|
||||
/* Special case for empty strings */
|
||||
if (len == 0)
|
||||
Py_RETURN_FALSE;
|
||||
|
||||
e = p + len;
|
||||
for (; p < e; p++) {
|
||||
if (!Py_ISSPACE(*p))
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_isalpha__doc__,
|
||||
"B.isalpha() -> bool\n\
|
||||
\n\
|
||||
Return True if all characters in B are alphabetic\n\
|
||||
and there is at least one character in B, False otherwise.");
|
||||
|
||||
PyObject*
|
||||
_Py_bytes_isalpha(const char *cptr, Py_ssize_t len)
|
||||
{
|
||||
const unsigned char *p
|
||||
= (unsigned char *) cptr;
|
||||
const unsigned char *e;
|
||||
|
||||
/* Shortcut for single character strings */
|
||||
if (len == 1 && Py_ISALPHA(*p))
|
||||
Py_RETURN_TRUE;
|
||||
|
||||
/* Special case for empty strings */
|
||||
if (len == 0)
|
||||
Py_RETURN_FALSE;
|
||||
|
||||
e = p + len;
|
||||
for (; p < e; p++) {
|
||||
if (!Py_ISALPHA(*p))
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_isalnum__doc__,
|
||||
"B.isalnum() -> bool\n\
|
||||
\n\
|
||||
Return True if all characters in B are alphanumeric\n\
|
||||
and there is at least one character in B, False otherwise.");
|
||||
|
||||
PyObject*
|
||||
_Py_bytes_isalnum(const char *cptr, Py_ssize_t len)
|
||||
{
|
||||
const unsigned char *p
|
||||
= (unsigned char *) cptr;
|
||||
const unsigned char *e;
|
||||
|
||||
/* Shortcut for single character strings */
|
||||
if (len == 1 && Py_ISALNUM(*p))
|
||||
Py_RETURN_TRUE;
|
||||
|
||||
/* Special case for empty strings */
|
||||
if (len == 0)
|
||||
Py_RETURN_FALSE;
|
||||
|
||||
e = p + len;
|
||||
for (; p < e; p++) {
|
||||
if (!Py_ISALNUM(*p))
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_isdigit__doc__,
|
||||
"B.isdigit() -> bool\n\
|
||||
\n\
|
||||
Return True if all characters in B are digits\n\
|
||||
and there is at least one character in B, False otherwise.");
|
||||
|
||||
PyObject*
|
||||
_Py_bytes_isdigit(const char *cptr, Py_ssize_t len)
|
||||
{
|
||||
const unsigned char *p
|
||||
= (unsigned char *) cptr;
|
||||
const unsigned char *e;
|
||||
|
||||
/* Shortcut for single character strings */
|
||||
if (len == 1 && Py_ISDIGIT(*p))
|
||||
Py_RETURN_TRUE;
|
||||
|
||||
/* Special case for empty strings */
|
||||
if (len == 0)
|
||||
Py_RETURN_FALSE;
|
||||
|
||||
e = p + len;
|
||||
for (; p < e; p++) {
|
||||
if (!Py_ISDIGIT(*p))
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_islower__doc__,
|
||||
"B.islower() -> bool\n\
|
||||
\n\
|
||||
Return True if all cased characters in B are lowercase and there is\n\
|
||||
at least one cased character in B, False otherwise.");
|
||||
|
||||
PyObject*
|
||||
_Py_bytes_islower(const char *cptr, Py_ssize_t len)
|
||||
{
|
||||
const unsigned char *p
|
||||
= (unsigned char *) cptr;
|
||||
const unsigned char *e;
|
||||
int cased;
|
||||
|
||||
/* Shortcut for single character strings */
|
||||
if (len == 1)
|
||||
return PyBool_FromLong(Py_ISLOWER(*p));
|
||||
|
||||
/* Special case for empty strings */
|
||||
if (len == 0)
|
||||
Py_RETURN_FALSE;
|
||||
|
||||
e = p + len;
|
||||
cased = 0;
|
||||
for (; p < e; p++) {
|
||||
if (Py_ISUPPER(*p))
|
||||
Py_RETURN_FALSE;
|
||||
else if (!cased && Py_ISLOWER(*p))
|
||||
cased = 1;
|
||||
}
|
||||
return PyBool_FromLong(cased);
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_isupper__doc__,
|
||||
"B.isupper() -> bool\n\
|
||||
\n\
|
||||
Return True if all cased characters in B are uppercase and there is\n\
|
||||
at least one cased character in B, False otherwise.");
|
||||
|
||||
PyObject*
|
||||
_Py_bytes_isupper(const char *cptr, Py_ssize_t len)
|
||||
{
|
||||
const unsigned char *p
|
||||
= (unsigned char *) cptr;
|
||||
const unsigned char *e;
|
||||
int cased;
|
||||
|
||||
/* Shortcut for single character strings */
|
||||
if (len == 1)
|
||||
return PyBool_FromLong(Py_ISUPPER(*p));
|
||||
|
||||
/* Special case for empty strings */
|
||||
if (len == 0)
|
||||
Py_RETURN_FALSE;
|
||||
|
||||
e = p + len;
|
||||
cased = 0;
|
||||
for (; p < e; p++) {
|
||||
if (Py_ISLOWER(*p))
|
||||
Py_RETURN_FALSE;
|
||||
else if (!cased && Py_ISUPPER(*p))
|
||||
cased = 1;
|
||||
}
|
||||
return PyBool_FromLong(cased);
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_istitle__doc__,
|
||||
"B.istitle() -> bool\n\
|
||||
\n\
|
||||
Return True if B is a titlecased string and there is at least one\n\
|
||||
character in B, i.e. uppercase characters may only follow uncased\n\
|
||||
characters and lowercase characters only cased ones. Return False\n\
|
||||
otherwise.");
|
||||
|
||||
PyObject*
|
||||
_Py_bytes_istitle(const char *cptr, Py_ssize_t len)
|
||||
{
|
||||
const unsigned char *p
|
||||
= (unsigned char *) cptr;
|
||||
const unsigned char *e;
|
||||
int cased, previous_is_cased;
|
||||
|
||||
/* Shortcut for single character strings */
|
||||
if (len == 1)
|
||||
return PyBool_FromLong(Py_ISUPPER(*p));
|
||||
|
||||
/* Special case for empty strings */
|
||||
if (len == 0)
|
||||
Py_RETURN_FALSE;
|
||||
|
||||
e = p + len;
|
||||
cased = 0;
|
||||
previous_is_cased = 0;
|
||||
for (; p < e; p++) {
|
||||
const unsigned char ch = *p;
|
||||
|
||||
if (Py_ISUPPER(ch)) {
|
||||
if (previous_is_cased)
|
||||
Py_RETURN_FALSE;
|
||||
previous_is_cased = 1;
|
||||
cased = 1;
|
||||
}
|
||||
else if (Py_ISLOWER(ch)) {
|
||||
if (!previous_is_cased)
|
||||
Py_RETURN_FALSE;
|
||||
previous_is_cased = 1;
|
||||
cased = 1;
|
||||
}
|
||||
else
|
||||
previous_is_cased = 0;
|
||||
}
|
||||
return PyBool_FromLong(cased);
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_lower__doc__,
|
||||
"B.lower() -> copy of B\n\
|
||||
\n\
|
||||
Return a copy of B with all ASCII characters converted to lowercase.");
|
||||
|
||||
void
|
||||
_Py_bytes_lower(char *result, const char *cptr, Py_ssize_t len)
|
||||
{
|
||||
Py_ssize_t i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
result[i] = Py_TOLOWER((unsigned char) cptr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_upper__doc__,
|
||||
"B.upper() -> copy of B\n\
|
||||
\n\
|
||||
Return a copy of B with all ASCII characters converted to uppercase.");
|
||||
|
||||
void
|
||||
_Py_bytes_upper(char *result, const char *cptr, Py_ssize_t len)
|
||||
{
|
||||
Py_ssize_t i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
result[i] = Py_TOUPPER((unsigned char) cptr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_title__doc__,
|
||||
"B.title() -> copy of B\n\
|
||||
\n\
|
||||
Return a titlecased version of B, i.e. ASCII words start with uppercase\n\
|
||||
characters, all remaining cased characters have lowercase.");
|
||||
|
||||
void
|
||||
_Py_bytes_title(char *result, const char *s, Py_ssize_t len)
|
||||
{
|
||||
Py_ssize_t i;
|
||||
int previous_is_cased = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int c = Py_CHARMASK(*s++);
|
||||
if (Py_ISLOWER(c)) {
|
||||
if (!previous_is_cased)
|
||||
c = Py_TOUPPER(c);
|
||||
previous_is_cased = 1;
|
||||
} else if (Py_ISUPPER(c)) {
|
||||
if (previous_is_cased)
|
||||
c = Py_TOLOWER(c);
|
||||
previous_is_cased = 1;
|
||||
} else
|
||||
previous_is_cased = 0;
|
||||
*result++ = c;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_capitalize__doc__,
|
||||
"B.capitalize() -> copy of B\n\
|
||||
\n\
|
||||
Return a copy of B with only its first character capitalized (ASCII)\n\
|
||||
and the rest lower-cased.");
|
||||
|
||||
void
|
||||
_Py_bytes_capitalize(char *result, const char *s, Py_ssize_t len)
|
||||
{
|
||||
Py_ssize_t i;
|
||||
|
||||
if (0 < len) {
|
||||
int c = Py_CHARMASK(*s++);
|
||||
if (Py_ISLOWER(c))
|
||||
*result = Py_TOUPPER(c);
|
||||
else
|
||||
*result = c;
|
||||
result++;
|
||||
}
|
||||
for (i = 1; i < len; i++) {
|
||||
int c = Py_CHARMASK(*s++);
|
||||
if (Py_ISUPPER(c))
|
||||
*result = Py_TOLOWER(c);
|
||||
else
|
||||
*result = c;
|
||||
result++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_swapcase__doc__,
|
||||
"B.swapcase() -> copy of B\n\
|
||||
\n\
|
||||
Return a copy of B with uppercase ASCII characters converted\n\
|
||||
to lowercase ASCII and vice versa.");
|
||||
|
||||
void
|
||||
_Py_bytes_swapcase(char *result, const char *s, Py_ssize_t len)
|
||||
{
|
||||
Py_ssize_t i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int c = Py_CHARMASK(*s++);
|
||||
if (Py_ISLOWER(c)) {
|
||||
*result = Py_TOUPPER(c);
|
||||
}
|
||||
else if (Py_ISUPPER(c)) {
|
||||
*result = Py_TOLOWER(c);
|
||||
}
|
||||
else
|
||||
*result = c;
|
||||
result++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_maketrans__doc__,
|
||||
"B.maketrans(frm, to) -> translation table\n\
|
||||
\n\
|
||||
Return a translation table (a bytes object of length 256) suitable\n\
|
||||
for use in the bytes or bytearray translate method where each byte\n\
|
||||
in frm is mapped to the byte at the same position in to.\n\
|
||||
The bytes objects frm and to must be of the same length.");
|
||||
|
||||
PyObject *
|
||||
_Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to)
|
||||
{
|
||||
PyObject *res = NULL;
|
||||
Py_ssize_t i;
|
||||
char *p;
|
||||
|
||||
if (frm->len != to->len) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"maketrans arguments must have same length");
|
||||
return NULL;
|
||||
}
|
||||
res = PyBytes_FromStringAndSize(NULL, 256);
|
||||
if (!res)
|
||||
return NULL;
|
||||
p = PyBytes_AS_STRING(res);
|
||||
for (i = 0; i < 256; i++)
|
||||
p[i] = (char) i;
|
||||
for (i = 0; i < frm->len; i++) {
|
||||
p[((unsigned char *)frm->buf)[i]] = ((char *)to->buf)[i];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#define FASTSEARCH fastsearch
|
||||
#define STRINGLIB(F) stringlib_##F
|
||||
#define STRINGLIB_CHAR char
|
||||
#define STRINGLIB_SIZEOF_CHAR 1
|
||||
|
||||
#include "stringlib/fastsearch.h"
|
||||
#include "stringlib/count.h"
|
||||
#include "stringlib/find.h"
|
||||
|
||||
/*
|
||||
Wraps stringlib_parse_args_finds() and additionally checks whether the
|
||||
first argument is an integer in range(0, 256).
|
||||
|
||||
If this is the case, writes the integer value to the byte parameter
|
||||
and sets subobj to NULL. Otherwise, sets the first argument to subobj
|
||||
and doesn't touch byte. The other parameters are similar to those of
|
||||
stringlib_parse_args_finds().
|
||||
*/
|
||||
|
||||
Py_LOCAL_INLINE(int)
|
||||
parse_args_finds_byte(const char *function_name, PyObject *args,
|
||||
PyObject **subobj, char *byte,
|
||||
Py_ssize_t *start, Py_ssize_t *end)
|
||||
{
|
||||
PyObject *tmp_subobj;
|
||||
Py_ssize_t ival;
|
||||
PyObject *err;
|
||||
|
||||
if(!stringlib_parse_args_finds(function_name, args, &tmp_subobj,
|
||||
start, end))
|
||||
return 0;
|
||||
|
||||
if (!PyNumber_Check(tmp_subobj)) {
|
||||
*subobj = tmp_subobj;
|
||||
return 1;
|
||||
}
|
||||
|
||||
ival = PyNumber_AsSsize_t(tmp_subobj, PyExc_OverflowError);
|
||||
if (ival == -1) {
|
||||
err = PyErr_Occurred();
|
||||
if (err && !PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) {
|
||||
PyErr_Clear();
|
||||
*subobj = tmp_subobj;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ival < 0 || ival > 255) {
|
||||
PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*subobj = NULL;
|
||||
*byte = (char)ival;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* helper macro to fixup start/end slice values */
|
||||
#define ADJUST_INDICES(start, end, len) \
|
||||
if (end > len) \
|
||||
end = len; \
|
||||
else if (end < 0) { \
|
||||
end += len; \
|
||||
if (end < 0) \
|
||||
end = 0; \
|
||||
} \
|
||||
if (start < 0) { \
|
||||
start += len; \
|
||||
if (start < 0) \
|
||||
start = 0; \
|
||||
}
|
||||
|
||||
Py_LOCAL_INLINE(Py_ssize_t)
|
||||
find_internal(const char *str, Py_ssize_t len,
|
||||
const char *function_name, PyObject *args, int dir)
|
||||
{
|
||||
PyObject *subobj;
|
||||
char byte;
|
||||
Py_buffer subbuf;
|
||||
const char *sub;
|
||||
Py_ssize_t sub_len;
|
||||
Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
|
||||
Py_ssize_t res;
|
||||
|
||||
if (!parse_args_finds_byte(function_name, args,
|
||||
&subobj, &byte, &start, &end))
|
||||
return -2;
|
||||
|
||||
if (subobj) {
|
||||
if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0)
|
||||
return -2;
|
||||
|
||||
sub = subbuf.buf;
|
||||
sub_len = subbuf.len;
|
||||
}
|
||||
else {
|
||||
sub = &byte;
|
||||
sub_len = 1;
|
||||
}
|
||||
|
||||
ADJUST_INDICES(start, end, len);
|
||||
if (end - start < sub_len)
|
||||
res = -1;
|
||||
else if (sub_len == 1) {
|
||||
if (dir > 0)
|
||||
res = stringlib_find_char(
|
||||
str + start, end - start,
|
||||
*sub);
|
||||
else
|
||||
res = stringlib_rfind_char(
|
||||
str + start, end - start,
|
||||
*sub);
|
||||
if (res >= 0)
|
||||
res += start;
|
||||
}
|
||||
else {
|
||||
if (dir > 0)
|
||||
res = stringlib_find_slice(
|
||||
str, len,
|
||||
sub, sub_len, start, end);
|
||||
else
|
||||
res = stringlib_rfind_slice(
|
||||
str, len,
|
||||
sub, sub_len, start, end);
|
||||
}
|
||||
|
||||
if (subobj)
|
||||
PyBuffer_Release(&subbuf);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_find__doc__,
|
||||
"B.find(sub[, start[, end]]) -> int\n\
|
||||
\n\
|
||||
Return the lowest index in B where subsection sub is found,\n\
|
||||
such that sub is contained within B[start,end]. Optional\n\
|
||||
arguments start and end are interpreted as in slice notation.\n\
|
||||
\n\
|
||||
Return -1 on failure.");
|
||||
|
||||
PyObject *
|
||||
_Py_bytes_find(const char *str, Py_ssize_t len, PyObject *args)
|
||||
{
|
||||
Py_ssize_t result = find_internal(str, len, "find", args, +1);
|
||||
if (result == -2)
|
||||
return NULL;
|
||||
return PyLong_FromSsize_t(result);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_index__doc__,
|
||||
"B.index(sub[, start[, end]]) -> int\n\
|
||||
\n\
|
||||
Return the lowest index in B where subsection sub is found,\n\
|
||||
such that sub is contained within B[start,end]. Optional\n\
|
||||
arguments start and end are interpreted as in slice notation.\n\
|
||||
\n\
|
||||
Raises ValueError when the subsection is not found.");
|
||||
|
||||
PyObject *
|
||||
_Py_bytes_index(const char *str, Py_ssize_t len, PyObject *args)
|
||||
{
|
||||
Py_ssize_t result = find_internal(str, len, "index", args, +1);
|
||||
if (result == -2)
|
||||
return NULL;
|
||||
if (result == -1) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"subsection not found");
|
||||
return NULL;
|
||||
}
|
||||
return PyLong_FromSsize_t(result);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_rfind__doc__,
|
||||
"B.rfind(sub[, start[, end]]) -> int\n\
|
||||
\n\
|
||||
Return the highest index in B where subsection sub is found,\n\
|
||||
such that sub is contained within B[start,end]. Optional\n\
|
||||
arguments start and end are interpreted as in slice notation.\n\
|
||||
\n\
|
||||
Return -1 on failure.");
|
||||
|
||||
PyObject *
|
||||
_Py_bytes_rfind(const char *str, Py_ssize_t len, PyObject *args)
|
||||
{
|
||||
Py_ssize_t result = find_internal(str, len, "rfind", args, -1);
|
||||
if (result == -2)
|
||||
return NULL;
|
||||
return PyLong_FromSsize_t(result);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_rindex__doc__,
|
||||
"B.rindex(sub[, start[, end]]) -> int\n\
|
||||
\n\
|
||||
Return the highest index in B where subsection sub is found,\n\
|
||||
such that sub is contained within B[start,end]. Optional\n\
|
||||
arguments start and end are interpreted as in slice notation.\n\
|
||||
\n\
|
||||
Raise ValueError when the subsection is not found.");
|
||||
|
||||
PyObject *
|
||||
_Py_bytes_rindex(const char *str, Py_ssize_t len, PyObject *args)
|
||||
{
|
||||
Py_ssize_t result = find_internal(str, len, "rindex", args, -1);
|
||||
if (result == -2)
|
||||
return NULL;
|
||||
if (result == -1) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"subsection not found");
|
||||
return NULL;
|
||||
}
|
||||
return PyLong_FromSsize_t(result);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_count__doc__,
|
||||
"B.count(sub[, start[, end]]) -> int\n\
|
||||
\n\
|
||||
Return the number of non-overlapping occurrences of subsection sub in\n\
|
||||
bytes B[start:end]. Optional arguments start and end are interpreted\n\
|
||||
as in slice notation.");
|
||||
|
||||
PyObject *
|
||||
_Py_bytes_count(const char *str, Py_ssize_t len, PyObject *args)
|
||||
{
|
||||
PyObject *sub_obj;
|
||||
const char *sub;
|
||||
Py_ssize_t sub_len;
|
||||
char byte;
|
||||
Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
|
||||
|
||||
Py_buffer vsub;
|
||||
PyObject *count_obj;
|
||||
|
||||
if (!parse_args_finds_byte("count", args,
|
||||
&sub_obj, &byte, &start, &end))
|
||||
return NULL;
|
||||
|
||||
if (sub_obj) {
|
||||
if (PyObject_GetBuffer(sub_obj, &vsub, PyBUF_SIMPLE) != 0)
|
||||
return NULL;
|
||||
|
||||
sub = vsub.buf;
|
||||
sub_len = vsub.len;
|
||||
}
|
||||
else {
|
||||
sub = &byte;
|
||||
sub_len = 1;
|
||||
}
|
||||
|
||||
ADJUST_INDICES(start, end, len);
|
||||
|
||||
count_obj = PyLong_FromSsize_t(
|
||||
stringlib_count(str + start, end - start, sub, sub_len, PY_SSIZE_T_MAX)
|
||||
);
|
||||
|
||||
if (sub_obj)
|
||||
PyBuffer_Release(&vsub);
|
||||
|
||||
return count_obj;
|
||||
}
|
||||
|
||||
int
|
||||
_Py_bytes_contains(const char *str, Py_ssize_t len, PyObject *arg)
|
||||
{
|
||||
Py_ssize_t ival = PyNumber_AsSsize_t(arg, NULL);
|
||||
if (ival == -1 && PyErr_Occurred()) {
|
||||
Py_buffer varg;
|
||||
Py_ssize_t pos;
|
||||
PyErr_Clear();
|
||||
if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0)
|
||||
return -1;
|
||||
pos = stringlib_find(str, len,
|
||||
varg.buf, varg.len, 0);
|
||||
PyBuffer_Release(&varg);
|
||||
return pos >= 0;
|
||||
}
|
||||
if (ival < 0 || ival >= 256) {
|
||||
PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return memchr(str, (int) ival, len) != NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Matches the end (direction >= 0) or start (direction < 0) of the buffer
|
||||
* against substr, using the start and end arguments. Returns
|
||||
* -1 on error, 0 if not found and 1 if found.
|
||||
*/
|
||||
static int
|
||||
tailmatch(const char *str, Py_ssize_t len, PyObject *substr,
|
||||
Py_ssize_t start, Py_ssize_t end, int direction)
|
||||
{
|
||||
Py_buffer sub_view = {NULL, NULL};
|
||||
const char *sub;
|
||||
Py_ssize_t slen;
|
||||
|
||||
if (PyBytes_Check(substr)) {
|
||||
sub = PyBytes_AS_STRING(substr);
|
||||
slen = PyBytes_GET_SIZE(substr);
|
||||
}
|
||||
else {
|
||||
if (PyObject_GetBuffer(substr, &sub_view, PyBUF_SIMPLE) != 0)
|
||||
return -1;
|
||||
sub = sub_view.buf;
|
||||
slen = sub_view.len;
|
||||
}
|
||||
|
||||
ADJUST_INDICES(start, end, len);
|
||||
|
||||
if (direction < 0) {
|
||||
/* startswith */
|
||||
if (start + slen > len)
|
||||
goto notfound;
|
||||
} else {
|
||||
/* endswith */
|
||||
if (end - start < slen || start > len)
|
||||
goto notfound;
|
||||
|
||||
if (end - slen > start)
|
||||
start = end - slen;
|
||||
}
|
||||
if (end - start < slen)
|
||||
goto notfound;
|
||||
if (memcmp(str + start, sub, slen) != 0)
|
||||
goto notfound;
|
||||
|
||||
PyBuffer_Release(&sub_view);
|
||||
return 1;
|
||||
|
||||
notfound:
|
||||
PyBuffer_Release(&sub_view);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
_Py_bytes_tailmatch(const char *str, Py_ssize_t len,
|
||||
const char *function_name, PyObject *args,
|
||||
int direction)
|
||||
{
|
||||
Py_ssize_t start = 0;
|
||||
Py_ssize_t end = PY_SSIZE_T_MAX;
|
||||
PyObject *subobj;
|
||||
int result;
|
||||
|
||||
if (!stringlib_parse_args_finds(function_name, args, &subobj, &start, &end))
|
||||
return NULL;
|
||||
if (PyTuple_Check(subobj)) {
|
||||
Py_ssize_t i;
|
||||
for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) {
|
||||
result = tailmatch(str, len, PyTuple_GET_ITEM(subobj, i),
|
||||
start, end, direction);
|
||||
if (result == -1)
|
||||
return NULL;
|
||||
else if (result) {
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
}
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
result = tailmatch(str, len, subobj, start, end, direction);
|
||||
if (result == -1) {
|
||||
if (PyErr_ExceptionMatches(PyExc_TypeError))
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%s first arg must be bytes or a tuple of bytes, "
|
||||
"not %s",
|
||||
function_name, Py_TYPE(subobj)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return PyBool_FromLong(result);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_startswith__doc__,
|
||||
"B.startswith(prefix[, start[, end]]) -> bool\n\
|
||||
\n\
|
||||
Return True if B starts with the specified prefix, False otherwise.\n\
|
||||
With optional start, test B beginning at that position.\n\
|
||||
With optional end, stop comparing B at that position.\n\
|
||||
prefix can also be a tuple of bytes to try.");
|
||||
|
||||
PyObject *
|
||||
_Py_bytes_startswith(const char *str, Py_ssize_t len, PyObject *args)
|
||||
{
|
||||
return _Py_bytes_tailmatch(str, len, "startswith", args, -1);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_endswith__doc__,
|
||||
"B.endswith(suffix[, start[, end]]) -> bool\n\
|
||||
\n\
|
||||
Return True if B ends with the specified suffix, False otherwise.\n\
|
||||
With optional start, test B beginning at that position.\n\
|
||||
With optional end, stop comparing B at that position.\n\
|
||||
suffix can also be a tuple of bytes to try.");
|
||||
|
||||
PyObject *
|
||||
_Py_bytes_endswith(const char *str, Py_ssize_t len, PyObject *args)
|
||||
{
|
||||
return _Py_bytes_tailmatch(str, len, "endswith", args, +1);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_expandtabs__doc__,
|
||||
"B.expandtabs(tabsize=8) -> copy of B\n\
|
||||
\n\
|
||||
Return a copy of B where all tab characters are expanded using spaces.\n\
|
||||
If tabsize is not given, a tab size of 8 characters is assumed.");
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_ljust__doc__,
|
||||
"B.ljust(width[, fillchar]) -> copy of B\n"
|
||||
"\n"
|
||||
"Return B left justified in a string of length width. Padding is\n"
|
||||
"done using the specified fill character (default is a space).");
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_rjust__doc__,
|
||||
"B.rjust(width[, fillchar]) -> copy of B\n"
|
||||
"\n"
|
||||
"Return B right justified in a string of length width. Padding is\n"
|
||||
"done using the specified fill character (default is a space)");
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_center__doc__,
|
||||
"B.center(width[, fillchar]) -> copy of B\n"
|
||||
"\n"
|
||||
"Return B centered in a string of length width. Padding is\n"
|
||||
"done using the specified fill character (default is a space).");
|
||||
|
||||
PyDoc_STRVAR_shared(_Py_zfill__doc__,
|
||||
"B.zfill(width) -> copy of B\n"
|
||||
"\n"
|
||||
"Pad a numeric string B with zeros on the left, to fill a field\n"
|
||||
"of the specified width. B is never truncated.");
|
3470
third_party/python/Objects/bytesobject.c
vendored
Normal file
3470
third_party/python/Objects/bytesobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
324
third_party/python/Objects/capsule.c
vendored
Normal file
324
third_party/python/Objects/capsule.c
vendored
Normal file
|
@ -0,0 +1,324 @@
|
|||
/* Wrap void * pointers to be passed between C modules */
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
/* Internal structure of PyCapsule */
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
void *pointer;
|
||||
const char *name;
|
||||
void *context;
|
||||
PyCapsule_Destructor destructor;
|
||||
} PyCapsule;
|
||||
|
||||
|
||||
|
||||
static int
|
||||
_is_legal_capsule(PyCapsule *capsule, const char *invalid_capsule)
|
||||
{
|
||||
if (!capsule || !PyCapsule_CheckExact(capsule) || capsule->pointer == NULL) {
|
||||
PyErr_SetString(PyExc_ValueError, invalid_capsule);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define is_legal_capsule(capsule, name) \
|
||||
(_is_legal_capsule(capsule, \
|
||||
name " called with invalid PyCapsule object"))
|
||||
|
||||
|
||||
static int
|
||||
name_matches(const char *name1, const char *name2) {
|
||||
/* if either is NULL, */
|
||||
if (!name1 || !name2) {
|
||||
/* they're only the same if they're both NULL. */
|
||||
return name1 == name2;
|
||||
}
|
||||
return !strcmp(name1, name2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
PyObject *
|
||||
PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
|
||||
{
|
||||
PyCapsule *capsule;
|
||||
|
||||
if (!pointer) {
|
||||
PyErr_SetString(PyExc_ValueError, "PyCapsule_New called with null pointer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
capsule = PyObject_NEW(PyCapsule, &PyCapsule_Type);
|
||||
if (capsule == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
capsule->pointer = pointer;
|
||||
capsule->name = name;
|
||||
capsule->context = NULL;
|
||||
capsule->destructor = destructor;
|
||||
|
||||
return (PyObject *)capsule;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PyCapsule_IsValid(PyObject *o, const char *name)
|
||||
{
|
||||
PyCapsule *capsule = (PyCapsule *)o;
|
||||
|
||||
return (capsule != NULL &&
|
||||
PyCapsule_CheckExact(capsule) &&
|
||||
capsule->pointer != NULL &&
|
||||
name_matches(capsule->name, name));
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
PyCapsule_GetPointer(PyObject *o, const char *name)
|
||||
{
|
||||
PyCapsule *capsule = (PyCapsule *)o;
|
||||
|
||||
if (!is_legal_capsule(capsule, "PyCapsule_GetPointer")) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!name_matches(name, capsule->name)) {
|
||||
PyErr_SetString(PyExc_ValueError, "PyCapsule_GetPointer called with incorrect name");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return capsule->pointer;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
PyCapsule_GetName(PyObject *o)
|
||||
{
|
||||
PyCapsule *capsule = (PyCapsule *)o;
|
||||
|
||||
if (!is_legal_capsule(capsule, "PyCapsule_GetName")) {
|
||||
return NULL;
|
||||
}
|
||||
return capsule->name;
|
||||
}
|
||||
|
||||
|
||||
PyCapsule_Destructor
|
||||
PyCapsule_GetDestructor(PyObject *o)
|
||||
{
|
||||
PyCapsule *capsule = (PyCapsule *)o;
|
||||
|
||||
if (!is_legal_capsule(capsule, "PyCapsule_GetDestructor")) {
|
||||
return NULL;
|
||||
}
|
||||
return capsule->destructor;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
PyCapsule_GetContext(PyObject *o)
|
||||
{
|
||||
PyCapsule *capsule = (PyCapsule *)o;
|
||||
|
||||
if (!is_legal_capsule(capsule, "PyCapsule_GetContext")) {
|
||||
return NULL;
|
||||
}
|
||||
return capsule->context;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PyCapsule_SetPointer(PyObject *o, void *pointer)
|
||||
{
|
||||
PyCapsule *capsule = (PyCapsule *)o;
|
||||
|
||||
if (!pointer) {
|
||||
PyErr_SetString(PyExc_ValueError, "PyCapsule_SetPointer called with null pointer");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!is_legal_capsule(capsule, "PyCapsule_SetPointer")) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
capsule->pointer = pointer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PyCapsule_SetName(PyObject *o, const char *name)
|
||||
{
|
||||
PyCapsule *capsule = (PyCapsule *)o;
|
||||
|
||||
if (!is_legal_capsule(capsule, "PyCapsule_SetName")) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
capsule->name = name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PyCapsule_SetDestructor(PyObject *o, PyCapsule_Destructor destructor)
|
||||
{
|
||||
PyCapsule *capsule = (PyCapsule *)o;
|
||||
|
||||
if (!is_legal_capsule(capsule, "PyCapsule_SetDestructor")) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
capsule->destructor = destructor;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PyCapsule_SetContext(PyObject *o, void *context)
|
||||
{
|
||||
PyCapsule *capsule = (PyCapsule *)o;
|
||||
|
||||
if (!is_legal_capsule(capsule, "PyCapsule_SetContext")) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
capsule->context = context;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
PyCapsule_Import(const char *name, int no_block)
|
||||
{
|
||||
PyObject *object = NULL;
|
||||
void *return_value = NULL;
|
||||
char *trace;
|
||||
size_t name_length = (strlen(name) + 1) * sizeof(char);
|
||||
char *name_dup = (char *)PyMem_MALLOC(name_length);
|
||||
|
||||
if (!name_dup) {
|
||||
return PyErr_NoMemory();
|
||||
}
|
||||
|
||||
memcpy(name_dup, name, name_length);
|
||||
|
||||
trace = name_dup;
|
||||
while (trace) {
|
||||
char *dot = strchr(trace, '.');
|
||||
if (dot) {
|
||||
*dot++ = '\0';
|
||||
}
|
||||
|
||||
if (object == NULL) {
|
||||
if (no_block) {
|
||||
object = PyImport_ImportModuleNoBlock(trace);
|
||||
} else {
|
||||
object = PyImport_ImportModule(trace);
|
||||
if (!object) {
|
||||
PyErr_Format(PyExc_ImportError, "PyCapsule_Import could not import module \"%s\"", trace);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PyObject *object2 = PyObject_GetAttrString(object, trace);
|
||||
Py_DECREF(object);
|
||||
object = object2;
|
||||
}
|
||||
if (!object) {
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
trace = dot;
|
||||
}
|
||||
|
||||
/* compare attribute name to module.name by hand */
|
||||
if (PyCapsule_IsValid(object, name)) {
|
||||
PyCapsule *capsule = (PyCapsule *)object;
|
||||
return_value = capsule->pointer;
|
||||
} else {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"PyCapsule_Import \"%s\" is not valid",
|
||||
name);
|
||||
}
|
||||
|
||||
EXIT:
|
||||
Py_XDECREF(object);
|
||||
if (name_dup) {
|
||||
PyMem_FREE(name_dup);
|
||||
}
|
||||
return return_value;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
capsule_dealloc(PyObject *o)
|
||||
{
|
||||
PyCapsule *capsule = (PyCapsule *)o;
|
||||
if (capsule->destructor) {
|
||||
capsule->destructor(o);
|
||||
}
|
||||
PyObject_DEL(o);
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
capsule_repr(PyObject *o)
|
||||
{
|
||||
PyCapsule *capsule = (PyCapsule *)o;
|
||||
const char *name;
|
||||
const char *quote;
|
||||
|
||||
if (capsule->name) {
|
||||
quote = "\"";
|
||||
name = capsule->name;
|
||||
} else {
|
||||
quote = "";
|
||||
name = "NULL";
|
||||
}
|
||||
|
||||
return PyUnicode_FromFormat("<capsule object %s%s%s at %p>",
|
||||
quote, name, quote, capsule);
|
||||
}
|
||||
|
||||
|
||||
|
||||
PyDoc_STRVAR(PyCapsule_Type__doc__,
|
||||
"Capsule objects let you wrap a C \"void *\" pointer in a Python\n\
|
||||
object. They're a way of passing data through the Python interpreter\n\
|
||||
without creating your own custom type.\n\
|
||||
\n\
|
||||
Capsules are used for communication between extension modules.\n\
|
||||
They provide a way for an extension module to export a C interface\n\
|
||||
to other extension modules, so that extension modules can use the\n\
|
||||
Python import mechanism to link to one another.\n\
|
||||
");
|
||||
|
||||
PyTypeObject PyCapsule_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"PyCapsule", /*tp_name*/
|
||||
sizeof(PyCapsule), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
/* methods */
|
||||
capsule_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_reserved*/
|
||||
capsule_repr, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
0, /*tp_flags*/
|
||||
PyCapsule_Type__doc__ /*tp_doc*/
|
||||
};
|
||||
|
||||
|
179
third_party/python/Objects/cellobject.c
vendored
Normal file
179
third_party/python/Objects/cellobject.c
vendored
Normal file
|
@ -0,0 +1,179 @@
|
|||
/* Cell object implementation */
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
PyObject *
|
||||
PyCell_New(PyObject *obj)
|
||||
{
|
||||
PyCellObject *op;
|
||||
|
||||
op = (PyCellObject *)PyObject_GC_New(PyCellObject, &PyCell_Type);
|
||||
if (op == NULL)
|
||||
return NULL;
|
||||
op->ob_ref = obj;
|
||||
Py_XINCREF(obj);
|
||||
|
||||
_PyObject_GC_TRACK(op);
|
||||
return (PyObject *)op;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyCell_Get(PyObject *op)
|
||||
{
|
||||
if (!PyCell_Check(op)) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
Py_XINCREF(((PyCellObject*)op)->ob_ref);
|
||||
return PyCell_GET(op);
|
||||
}
|
||||
|
||||
int
|
||||
PyCell_Set(PyObject *op, PyObject *obj)
|
||||
{
|
||||
PyObject* oldobj;
|
||||
if (!PyCell_Check(op)) {
|
||||
PyErr_BadInternalCall();
|
||||
return -1;
|
||||
}
|
||||
oldobj = PyCell_GET(op);
|
||||
Py_XINCREF(obj);
|
||||
PyCell_SET(op, obj);
|
||||
Py_XDECREF(oldobj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
cell_dealloc(PyCellObject *op)
|
||||
{
|
||||
_PyObject_GC_UNTRACK(op);
|
||||
Py_XDECREF(op->ob_ref);
|
||||
PyObject_GC_Del(op);
|
||||
}
|
||||
|
||||
#define TEST_COND(cond) ((cond) ? Py_True : Py_False)
|
||||
|
||||
static PyObject *
|
||||
cell_richcompare(PyObject *a, PyObject *b, int op)
|
||||
{
|
||||
int result;
|
||||
PyObject *v;
|
||||
|
||||
/* neither argument should be NULL, unless something's gone wrong */
|
||||
assert(a != NULL && b != NULL);
|
||||
|
||||
/* both arguments should be instances of PyCellObject */
|
||||
if (!PyCell_Check(a) || !PyCell_Check(b)) {
|
||||
v = Py_NotImplemented;
|
||||
Py_INCREF(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
/* compare cells by contents; empty cells come before anything else */
|
||||
a = ((PyCellObject *)a)->ob_ref;
|
||||
b = ((PyCellObject *)b)->ob_ref;
|
||||
if (a != NULL && b != NULL)
|
||||
return PyObject_RichCompare(a, b, op);
|
||||
|
||||
result = (b == NULL) - (a == NULL);
|
||||
switch (op) {
|
||||
case Py_EQ:
|
||||
v = TEST_COND(result == 0);
|
||||
break;
|
||||
case Py_NE:
|
||||
v = TEST_COND(result != 0);
|
||||
break;
|
||||
case Py_LE:
|
||||
v = TEST_COND(result <= 0);
|
||||
break;
|
||||
case Py_GE:
|
||||
v = TEST_COND(result >= 0);
|
||||
break;
|
||||
case Py_LT:
|
||||
v = TEST_COND(result < 0);
|
||||
break;
|
||||
case Py_GT:
|
||||
v = TEST_COND(result > 0);
|
||||
break;
|
||||
default:
|
||||
PyErr_BadArgument();
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cell_repr(PyCellObject *op)
|
||||
{
|
||||
if (op->ob_ref == NULL)
|
||||
return PyUnicode_FromFormat("<cell at %p: empty>", op);
|
||||
|
||||
return PyUnicode_FromFormat("<cell at %p: %.80s object at %p>",
|
||||
op, op->ob_ref->ob_type->tp_name,
|
||||
op->ob_ref);
|
||||
}
|
||||
|
||||
static int
|
||||
cell_traverse(PyCellObject *op, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(op->ob_ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
cell_clear(PyCellObject *op)
|
||||
{
|
||||
Py_CLEAR(op->ob_ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cell_get_contents(PyCellObject *op, void *closure)
|
||||
{
|
||||
if (op->ob_ref == NULL)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "Cell is empty");
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(op->ob_ref);
|
||||
return op->ob_ref;
|
||||
}
|
||||
|
||||
static PyGetSetDef cell_getsetlist[] = {
|
||||
{"cell_contents", (getter)cell_get_contents, NULL},
|
||||
{NULL} /* sentinel */
|
||||
};
|
||||
|
||||
PyTypeObject PyCell_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"cell",
|
||||
sizeof(PyCellObject),
|
||||
0,
|
||||
(destructor)cell_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
(reprfunc)cell_repr, /* 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 | Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc)cell_traverse, /* tp_traverse */
|
||||
(inquiry)cell_clear, /* tp_clear */
|
||||
cell_richcompare, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
cell_getsetlist, /* tp_getset */
|
||||
};
|
645
third_party/python/Objects/classobject.c
vendored
Normal file
645
third_party/python/Objects/classobject.c
vendored
Normal file
|
@ -0,0 +1,645 @@
|
|||
/* Class object implementation (dead now except for methods) */
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
|
||||
#define TP_DESCR_GET(t) ((t)->tp_descr_get)
|
||||
|
||||
/* Free list for method objects to safe malloc/free overhead
|
||||
* The im_self element is used to chain the elements.
|
||||
*/
|
||||
static PyMethodObject *free_list;
|
||||
static int numfree = 0;
|
||||
#ifndef PyMethod_MAXFREELIST
|
||||
#define PyMethod_MAXFREELIST 256
|
||||
#endif
|
||||
|
||||
_Py_IDENTIFIER(__name__);
|
||||
_Py_IDENTIFIER(__qualname__);
|
||||
|
||||
PyObject *
|
||||
PyMethod_Function(PyObject *im)
|
||||
{
|
||||
if (!PyMethod_Check(im)) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
return ((PyMethodObject *)im)->im_func;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyMethod_Self(PyObject *im)
|
||||
{
|
||||
if (!PyMethod_Check(im)) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
return ((PyMethodObject *)im)->im_self;
|
||||
}
|
||||
|
||||
/* Method objects are used for bound instance methods returned by
|
||||
instancename.methodname. ClassName.methodname returns an ordinary
|
||||
function.
|
||||
*/
|
||||
|
||||
PyObject *
|
||||
PyMethod_New(PyObject *func, PyObject *self)
|
||||
{
|
||||
PyMethodObject *im;
|
||||
if (self == NULL) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
im = free_list;
|
||||
if (im != NULL) {
|
||||
free_list = (PyMethodObject *)(im->im_self);
|
||||
(void)PyObject_INIT(im, &PyMethod_Type);
|
||||
numfree--;
|
||||
}
|
||||
else {
|
||||
im = PyObject_GC_New(PyMethodObject, &PyMethod_Type);
|
||||
if (im == NULL)
|
||||
return NULL;
|
||||
}
|
||||
im->im_weakreflist = NULL;
|
||||
Py_INCREF(func);
|
||||
im->im_func = func;
|
||||
Py_XINCREF(self);
|
||||
im->im_self = self;
|
||||
_PyObject_GC_TRACK(im);
|
||||
return (PyObject *)im;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
method_reduce(PyMethodObject *im)
|
||||
{
|
||||
PyObject *self = PyMethod_GET_SELF(im);
|
||||
PyObject *func = PyMethod_GET_FUNCTION(im);
|
||||
PyObject *funcname;
|
||||
_Py_IDENTIFIER(getattr);
|
||||
|
||||
funcname = _PyObject_GetAttrId(func, &PyId___name__);
|
||||
if (funcname == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return Py_BuildValue("N(ON)", _PyEval_GetBuiltinId(&PyId_getattr),
|
||||
self, funcname);
|
||||
}
|
||||
|
||||
static PyMethodDef method_methods[] = {
|
||||
{"__reduce__", (PyCFunction)method_reduce, METH_NOARGS, NULL},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* Descriptors for PyMethod attributes */
|
||||
|
||||
/* im_func and im_self are stored in the PyMethod object */
|
||||
|
||||
#define MO_OFF(x) offsetof(PyMethodObject, x)
|
||||
|
||||
static PyMemberDef method_memberlist[] = {
|
||||
{"__func__", T_OBJECT, MO_OFF(im_func), READONLY|RESTRICTED,
|
||||
"the function (or other callable) implementing a method"},
|
||||
{"__self__", T_OBJECT, MO_OFF(im_self), READONLY|RESTRICTED,
|
||||
"the instance to which a method is bound"},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
/* Christian Tismer argued convincingly that method attributes should
|
||||
(nearly) always override function attributes.
|
||||
The one exception is __doc__; there's a default __doc__ which
|
||||
should only be used for the class, not for instances */
|
||||
|
||||
static PyObject *
|
||||
method_get_doc(PyMethodObject *im, void *context)
|
||||
{
|
||||
static PyObject *docstr;
|
||||
if (docstr == NULL) {
|
||||
docstr= PyUnicode_InternFromString("__doc__");
|
||||
if (docstr == NULL)
|
||||
return NULL;
|
||||
}
|
||||
return PyObject_GetAttr(im->im_func, docstr);
|
||||
}
|
||||
|
||||
static PyGetSetDef method_getset[] = {
|
||||
{"__doc__", (getter)method_get_doc, NULL, NULL},
|
||||
{0}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
method_getattro(PyObject *obj, PyObject *name)
|
||||
{
|
||||
PyMethodObject *im = (PyMethodObject *)obj;
|
||||
PyTypeObject *tp = obj->ob_type;
|
||||
PyObject *descr = NULL;
|
||||
|
||||
{
|
||||
if (tp->tp_dict == NULL) {
|
||||
if (PyType_Ready(tp) < 0)
|
||||
return NULL;
|
||||
}
|
||||
descr = _PyType_Lookup(tp, name);
|
||||
}
|
||||
|
||||
if (descr != NULL) {
|
||||
descrgetfunc f = TP_DESCR_GET(descr->ob_type);
|
||||
if (f != NULL)
|
||||
return f(descr, obj, (PyObject *)obj->ob_type);
|
||||
else {
|
||||
Py_INCREF(descr);
|
||||
return descr;
|
||||
}
|
||||
}
|
||||
|
||||
return PyObject_GetAttr(im->im_func, name);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(method_doc,
|
||||
"method(function, instance)\n\
|
||||
\n\
|
||||
Create a bound instance method object.");
|
||||
|
||||
static PyObject *
|
||||
method_new(PyTypeObject* type, PyObject* args, PyObject *kw)
|
||||
{
|
||||
PyObject *func;
|
||||
PyObject *self;
|
||||
|
||||
if (!_PyArg_NoKeywords("method", kw))
|
||||
return NULL;
|
||||
if (!PyArg_UnpackTuple(args, "method", 2, 2,
|
||||
&func, &self))
|
||||
return NULL;
|
||||
if (!PyCallable_Check(func)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"first argument must be callable");
|
||||
return NULL;
|
||||
}
|
||||
if (self == NULL || self == Py_None) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"self must not be None");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyMethod_New(func, self);
|
||||
}
|
||||
|
||||
static void
|
||||
method_dealloc(PyMethodObject *im)
|
||||
{
|
||||
_PyObject_GC_UNTRACK(im);
|
||||
if (im->im_weakreflist != NULL)
|
||||
PyObject_ClearWeakRefs((PyObject *)im);
|
||||
Py_DECREF(im->im_func);
|
||||
Py_XDECREF(im->im_self);
|
||||
if (numfree < PyMethod_MAXFREELIST) {
|
||||
im->im_self = (PyObject *)free_list;
|
||||
free_list = im;
|
||||
numfree++;
|
||||
}
|
||||
else {
|
||||
PyObject_GC_Del(im);
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
method_richcompare(PyObject *self, PyObject *other, int op)
|
||||
{
|
||||
PyMethodObject *a, *b;
|
||||
PyObject *res;
|
||||
int eq;
|
||||
|
||||
if ((op != Py_EQ && op != Py_NE) ||
|
||||
!PyMethod_Check(self) ||
|
||||
!PyMethod_Check(other))
|
||||
{
|
||||
Py_RETURN_NOTIMPLEMENTED;
|
||||
}
|
||||
a = (PyMethodObject *)self;
|
||||
b = (PyMethodObject *)other;
|
||||
eq = PyObject_RichCompareBool(a->im_func, b->im_func, Py_EQ);
|
||||
if (eq == 1) {
|
||||
if (a->im_self == NULL || b->im_self == NULL)
|
||||
eq = a->im_self == b->im_self;
|
||||
else
|
||||
eq = PyObject_RichCompareBool(a->im_self, b->im_self,
|
||||
Py_EQ);
|
||||
}
|
||||
if (eq < 0)
|
||||
return NULL;
|
||||
if (op == Py_EQ)
|
||||
res = eq ? Py_True : Py_False;
|
||||
else
|
||||
res = eq ? Py_False : Py_True;
|
||||
Py_INCREF(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
method_repr(PyMethodObject *a)
|
||||
{
|
||||
PyObject *self = a->im_self;
|
||||
PyObject *func = a->im_func;
|
||||
PyObject *funcname = NULL, *result = NULL;
|
||||
const char *defname = "?";
|
||||
|
||||
funcname = _PyObject_GetAttrId(func, &PyId___qualname__);
|
||||
if (funcname == NULL) {
|
||||
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
|
||||
return NULL;
|
||||
PyErr_Clear();
|
||||
|
||||
funcname = _PyObject_GetAttrId(func, &PyId___name__);
|
||||
if (funcname == NULL) {
|
||||
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
|
||||
return NULL;
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (funcname != NULL && !PyUnicode_Check(funcname)) {
|
||||
Py_DECREF(funcname);
|
||||
funcname = NULL;
|
||||
}
|
||||
|
||||
/* XXX Shouldn't use repr()/%R here! */
|
||||
result = PyUnicode_FromFormat("<bound method %V of %R>",
|
||||
funcname, defname, self);
|
||||
|
||||
Py_XDECREF(funcname);
|
||||
return result;
|
||||
}
|
||||
|
||||
static Py_hash_t
|
||||
method_hash(PyMethodObject *a)
|
||||
{
|
||||
Py_hash_t x, y;
|
||||
if (a->im_self == NULL)
|
||||
x = PyObject_Hash(Py_None);
|
||||
else
|
||||
x = PyObject_Hash(a->im_self);
|
||||
if (x == -1)
|
||||
return -1;
|
||||
y = PyObject_Hash(a->im_func);
|
||||
if (y == -1)
|
||||
return -1;
|
||||
x = x ^ y;
|
||||
if (x == -1)
|
||||
x = -2;
|
||||
return x;
|
||||
}
|
||||
|
||||
static int
|
||||
method_traverse(PyMethodObject *im, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(im->im_func);
|
||||
Py_VISIT(im->im_self);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
method_call(PyObject *method, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
PyObject *self, *func;
|
||||
|
||||
self = PyMethod_GET_SELF(method);
|
||||
if (self == NULL) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
func = PyMethod_GET_FUNCTION(method);
|
||||
|
||||
return _PyObject_Call_Prepend(func, self, args, kwargs);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
method_descr_get(PyObject *meth, PyObject *obj, PyObject *cls)
|
||||
{
|
||||
/* Don't rebind an already bound method of a class that's not a base
|
||||
class of cls. */
|
||||
if (PyMethod_GET_SELF(meth) != NULL) {
|
||||
/* Already bound */
|
||||
Py_INCREF(meth);
|
||||
return meth;
|
||||
}
|
||||
/* Bind it to obj */
|
||||
return PyMethod_New(PyMethod_GET_FUNCTION(meth), obj);
|
||||
}
|
||||
|
||||
PyTypeObject PyMethod_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"method",
|
||||
sizeof(PyMethodObject),
|
||||
0,
|
||||
(destructor)method_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
(reprfunc)method_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
(hashfunc)method_hash, /* tp_hash */
|
||||
method_call, /* tp_call */
|
||||
0, /* tp_str */
|
||||
method_getattro, /* tp_getattro */
|
||||
PyObject_GenericSetAttr, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
method_doc, /* tp_doc */
|
||||
(traverseproc)method_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
method_richcompare, /* tp_richcompare */
|
||||
offsetof(PyMethodObject, im_weakreflist), /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
method_methods, /* tp_methods */
|
||||
method_memberlist, /* tp_members */
|
||||
method_getset, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
method_descr_get, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
method_new, /* tp_new */
|
||||
};
|
||||
|
||||
/* Clear out the free list */
|
||||
|
||||
int
|
||||
PyMethod_ClearFreeList(void)
|
||||
{
|
||||
int freelist_size = numfree;
|
||||
|
||||
while (free_list) {
|
||||
PyMethodObject *im = free_list;
|
||||
free_list = (PyMethodObject *)(im->im_self);
|
||||
PyObject_GC_Del(im);
|
||||
numfree--;
|
||||
}
|
||||
assert(numfree == 0);
|
||||
return freelist_size;
|
||||
}
|
||||
|
||||
void
|
||||
PyMethod_Fini(void)
|
||||
{
|
||||
(void)PyMethod_ClearFreeList();
|
||||
}
|
||||
|
||||
/* Print summary info about the state of the optimized allocator */
|
||||
void
|
||||
_PyMethod_DebugMallocStats(FILE *out)
|
||||
{
|
||||
_PyDebugAllocatorStats(out,
|
||||
"free PyMethodObject",
|
||||
numfree, sizeof(PyMethodObject));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* instance method
|
||||
*/
|
||||
|
||||
PyObject *
|
||||
PyInstanceMethod_New(PyObject *func) {
|
||||
PyInstanceMethodObject *method;
|
||||
method = PyObject_GC_New(PyInstanceMethodObject,
|
||||
&PyInstanceMethod_Type);
|
||||
if (method == NULL) return NULL;
|
||||
Py_INCREF(func);
|
||||
method->func = func;
|
||||
_PyObject_GC_TRACK(method);
|
||||
return (PyObject *)method;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyInstanceMethod_Function(PyObject *im)
|
||||
{
|
||||
if (!PyInstanceMethod_Check(im)) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
return PyInstanceMethod_GET_FUNCTION(im);
|
||||
}
|
||||
|
||||
#define IMO_OFF(x) offsetof(PyInstanceMethodObject, x)
|
||||
|
||||
static PyMemberDef instancemethod_memberlist[] = {
|
||||
{"__func__", T_OBJECT, IMO_OFF(func), READONLY|RESTRICTED,
|
||||
"the function (or other callable) implementing a method"},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
instancemethod_get_doc(PyObject *self, void *context)
|
||||
{
|
||||
static PyObject *docstr;
|
||||
if (docstr == NULL) {
|
||||
docstr = PyUnicode_InternFromString("__doc__");
|
||||
if (docstr == NULL)
|
||||
return NULL;
|
||||
}
|
||||
return PyObject_GetAttr(PyInstanceMethod_GET_FUNCTION(self), docstr);
|
||||
}
|
||||
|
||||
static PyGetSetDef instancemethod_getset[] = {
|
||||
{"__doc__", (getter)instancemethod_get_doc, NULL, NULL},
|
||||
{0}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
instancemethod_getattro(PyObject *self, PyObject *name)
|
||||
{
|
||||
PyTypeObject *tp = self->ob_type;
|
||||
PyObject *descr = NULL;
|
||||
|
||||
if (tp->tp_dict == NULL) {
|
||||
if (PyType_Ready(tp) < 0)
|
||||
return NULL;
|
||||
}
|
||||
descr = _PyType_Lookup(tp, name);
|
||||
|
||||
if (descr != NULL) {
|
||||
descrgetfunc f = TP_DESCR_GET(descr->ob_type);
|
||||
if (f != NULL)
|
||||
return f(descr, self, (PyObject *)self->ob_type);
|
||||
else {
|
||||
Py_INCREF(descr);
|
||||
return descr;
|
||||
}
|
||||
}
|
||||
|
||||
return PyObject_GetAttr(PyInstanceMethod_GET_FUNCTION(self), name);
|
||||
}
|
||||
|
||||
static void
|
||||
instancemethod_dealloc(PyObject *self) {
|
||||
_PyObject_GC_UNTRACK(self);
|
||||
Py_DECREF(PyInstanceMethod_GET_FUNCTION(self));
|
||||
PyObject_GC_Del(self);
|
||||
}
|
||||
|
||||
static int
|
||||
instancemethod_traverse(PyObject *self, visitproc visit, void *arg) {
|
||||
Py_VISIT(PyInstanceMethod_GET_FUNCTION(self));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
instancemethod_call(PyObject *self, PyObject *arg, PyObject *kw)
|
||||
{
|
||||
return PyObject_Call(PyMethod_GET_FUNCTION(self), arg, kw);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
instancemethod_descr_get(PyObject *descr, PyObject *obj, PyObject *type) {
|
||||
PyObject *func = PyInstanceMethod_GET_FUNCTION(descr);
|
||||
if (obj == NULL) {
|
||||
Py_INCREF(func);
|
||||
return func;
|
||||
}
|
||||
else
|
||||
return PyMethod_New(func, obj);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
instancemethod_richcompare(PyObject *self, PyObject *other, int op)
|
||||
{
|
||||
PyInstanceMethodObject *a, *b;
|
||||
PyObject *res;
|
||||
int eq;
|
||||
|
||||
if ((op != Py_EQ && op != Py_NE) ||
|
||||
!PyInstanceMethod_Check(self) ||
|
||||
!PyInstanceMethod_Check(other))
|
||||
{
|
||||
Py_RETURN_NOTIMPLEMENTED;
|
||||
}
|
||||
a = (PyInstanceMethodObject *)self;
|
||||
b = (PyInstanceMethodObject *)other;
|
||||
eq = PyObject_RichCompareBool(a->func, b->func, Py_EQ);
|
||||
if (eq < 0)
|
||||
return NULL;
|
||||
if (op == Py_EQ)
|
||||
res = eq ? Py_True : Py_False;
|
||||
else
|
||||
res = eq ? Py_False : Py_True;
|
||||
Py_INCREF(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
instancemethod_repr(PyObject *self)
|
||||
{
|
||||
PyObject *func = PyInstanceMethod_Function(self);
|
||||
PyObject *funcname = NULL , *result = NULL;
|
||||
char *defname = "?";
|
||||
|
||||
if (func == NULL) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
funcname = _PyObject_GetAttrId(func, &PyId___name__);
|
||||
if (funcname == NULL) {
|
||||
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
|
||||
return NULL;
|
||||
PyErr_Clear();
|
||||
}
|
||||
else if (!PyUnicode_Check(funcname)) {
|
||||
Py_DECREF(funcname);
|
||||
funcname = NULL;
|
||||
}
|
||||
|
||||
result = PyUnicode_FromFormat("<instancemethod %V at %p>",
|
||||
funcname, defname, self);
|
||||
|
||||
Py_XDECREF(funcname);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
static long
|
||||
instancemethod_hash(PyObject *self)
|
||||
{
|
||||
long x, y;
|
||||
x = (long)self;
|
||||
y = PyObject_Hash(PyInstanceMethod_GET_FUNCTION(self));
|
||||
if (y == -1)
|
||||
return -1;
|
||||
x = x ^ y;
|
||||
if (x == -1)
|
||||
x = -2;
|
||||
return x;
|
||||
}
|
||||
*/
|
||||
|
||||
PyDoc_STRVAR(instancemethod_doc,
|
||||
"instancemethod(function)\n\
|
||||
\n\
|
||||
Bind a function to a class.");
|
||||
|
||||
static PyObject *
|
||||
instancemethod_new(PyTypeObject* type, PyObject* args, PyObject *kw)
|
||||
{
|
||||
PyObject *func;
|
||||
|
||||
if (!_PyArg_NoKeywords("instancemethod", kw))
|
||||
return NULL;
|
||||
if (!PyArg_UnpackTuple(args, "instancemethod", 1, 1, &func))
|
||||
return NULL;
|
||||
if (!PyCallable_Check(func)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"first argument must be callable");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyInstanceMethod_New(func);
|
||||
}
|
||||
|
||||
PyTypeObject PyInstanceMethod_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"instancemethod", /* tp_name */
|
||||
sizeof(PyInstanceMethodObject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
instancemethod_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
(reprfunc)instancemethod_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /*(hashfunc)instancemethod_hash, tp_hash */
|
||||
instancemethod_call, /* tp_call */
|
||||
0, /* tp_str */
|
||||
instancemethod_getattro, /* tp_getattro */
|
||||
PyObject_GenericSetAttr, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT
|
||||
| Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
instancemethod_doc, /* tp_doc */
|
||||
instancemethod_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
instancemethod_richcompare, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
instancemethod_memberlist, /* tp_members */
|
||||
instancemethod_getset, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
instancemethod_descr_get, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
instancemethod_new, /* tp_new */
|
||||
};
|
715
third_party/python/Objects/clinic/bytearrayobject.c.h
generated
vendored
Normal file
715
third_party/python/Objects/clinic/bytearrayobject.c.h
generated
vendored
Normal file
|
@ -0,0 +1,715 @@
|
|||
/*[clinic input]
|
||||
preserve
|
||||
[clinic start generated code]*/
|
||||
|
||||
PyDoc_STRVAR(bytearray_clear__doc__,
|
||||
"clear($self, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Remove all items from the bytearray.");
|
||||
|
||||
#define BYTEARRAY_CLEAR_METHODDEF \
|
||||
{"clear", (PyCFunction)bytearray_clear, METH_NOARGS, bytearray_clear__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_clear_impl(PyByteArrayObject *self);
|
||||
|
||||
static PyObject *
|
||||
bytearray_clear(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return bytearray_clear_impl(self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_copy__doc__,
|
||||
"copy($self, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a copy of B.");
|
||||
|
||||
#define BYTEARRAY_COPY_METHODDEF \
|
||||
{"copy", (PyCFunction)bytearray_copy, METH_NOARGS, bytearray_copy__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_copy_impl(PyByteArrayObject *self);
|
||||
|
||||
static PyObject *
|
||||
bytearray_copy(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return bytearray_copy_impl(self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_translate__doc__,
|
||||
"translate($self, table, /, delete=b\'\')\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a copy with each character mapped by the given translation table.\n"
|
||||
"\n"
|
||||
" table\n"
|
||||
" Translation table, which must be a bytes object of length 256.\n"
|
||||
"\n"
|
||||
"All characters occurring in the optional argument delete are removed.\n"
|
||||
"The remaining characters are mapped through the given translation table.");
|
||||
|
||||
#define BYTEARRAY_TRANSLATE_METHODDEF \
|
||||
{"translate", (PyCFunction)bytearray_translate, METH_FASTCALL, bytearray_translate__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_translate_impl(PyByteArrayObject *self, PyObject *table,
|
||||
PyObject *deletechars);
|
||||
|
||||
static PyObject *
|
||||
bytearray_translate(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
static const char * const _keywords[] = {"", "delete", NULL};
|
||||
static _PyArg_Parser _parser = {"O|O:translate", _keywords, 0};
|
||||
PyObject *table;
|
||||
PyObject *deletechars = NULL;
|
||||
|
||||
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
|
||||
&table, &deletechars)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytearray_translate_impl(self, table, deletechars);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_maketrans__doc__,
|
||||
"maketrans(frm, to, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a translation table useable for the bytes or bytearray translate method.\n"
|
||||
"\n"
|
||||
"The returned table will be one where each byte in frm is mapped to the byte at\n"
|
||||
"the same position in to.\n"
|
||||
"\n"
|
||||
"The bytes objects frm and to must be of the same length.");
|
||||
|
||||
#define BYTEARRAY_MAKETRANS_METHODDEF \
|
||||
{"maketrans", (PyCFunction)bytearray_maketrans, METH_VARARGS|METH_STATIC, bytearray_maketrans__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_maketrans_impl(Py_buffer *frm, Py_buffer *to);
|
||||
|
||||
static PyObject *
|
||||
bytearray_maketrans(void *null, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
Py_buffer frm = {NULL, NULL};
|
||||
Py_buffer to = {NULL, NULL};
|
||||
|
||||
if (!PyArg_ParseTuple(args, "y*y*:maketrans",
|
||||
&frm, &to)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytearray_maketrans_impl(&frm, &to);
|
||||
|
||||
exit:
|
||||
/* Cleanup for frm */
|
||||
if (frm.obj) {
|
||||
PyBuffer_Release(&frm);
|
||||
}
|
||||
/* Cleanup for to */
|
||||
if (to.obj) {
|
||||
PyBuffer_Release(&to);
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_replace__doc__,
|
||||
"replace($self, old, new, count=-1, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a copy with all occurrences of substring old replaced by new.\n"
|
||||
"\n"
|
||||
" count\n"
|
||||
" Maximum number of occurrences to replace.\n"
|
||||
" -1 (the default value) means replace all occurrences.\n"
|
||||
"\n"
|
||||
"If the optional argument count is given, only the first count occurrences are\n"
|
||||
"replaced.");
|
||||
|
||||
#define BYTEARRAY_REPLACE_METHODDEF \
|
||||
{"replace", (PyCFunction)bytearray_replace, METH_VARARGS, bytearray_replace__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_replace_impl(PyByteArrayObject *self, Py_buffer *old,
|
||||
Py_buffer *new, Py_ssize_t count);
|
||||
|
||||
static PyObject *
|
||||
bytearray_replace(PyByteArrayObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
Py_buffer old = {NULL, NULL};
|
||||
Py_buffer new = {NULL, NULL};
|
||||
Py_ssize_t count = -1;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "y*y*|n:replace",
|
||||
&old, &new, &count)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytearray_replace_impl(self, &old, &new, count);
|
||||
|
||||
exit:
|
||||
/* Cleanup for old */
|
||||
if (old.obj) {
|
||||
PyBuffer_Release(&old);
|
||||
}
|
||||
/* Cleanup for new */
|
||||
if (new.obj) {
|
||||
PyBuffer_Release(&new);
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_split__doc__,
|
||||
"split($self, /, sep=None, maxsplit=-1)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a list of the sections in the bytearray, using sep as the delimiter.\n"
|
||||
"\n"
|
||||
" sep\n"
|
||||
" The delimiter according which to split the bytearray.\n"
|
||||
" None (the default value) means split on ASCII whitespace characters\n"
|
||||
" (space, tab, return, newline, formfeed, vertical tab).\n"
|
||||
" maxsplit\n"
|
||||
" Maximum number of splits to do.\n"
|
||||
" -1 (the default value) means no limit.");
|
||||
|
||||
#define BYTEARRAY_SPLIT_METHODDEF \
|
||||
{"split", (PyCFunction)bytearray_split, METH_FASTCALL, bytearray_split__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_split_impl(PyByteArrayObject *self, PyObject *sep,
|
||||
Py_ssize_t maxsplit);
|
||||
|
||||
static PyObject *
|
||||
bytearray_split(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
static const char * const _keywords[] = {"sep", "maxsplit", NULL};
|
||||
static _PyArg_Parser _parser = {"|On:split", _keywords, 0};
|
||||
PyObject *sep = Py_None;
|
||||
Py_ssize_t maxsplit = -1;
|
||||
|
||||
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
|
||||
&sep, &maxsplit)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytearray_split_impl(self, sep, maxsplit);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_partition__doc__,
|
||||
"partition($self, sep, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Partition the bytearray into three parts using the given separator.\n"
|
||||
"\n"
|
||||
"This will search for the separator sep in the bytearray. If the separator is\n"
|
||||
"found, returns a 3-tuple containing the part before the separator, the\n"
|
||||
"separator itself, and the part after it as new bytearray objects.\n"
|
||||
"\n"
|
||||
"If the separator is not found, returns a 3-tuple containing the copy of the\n"
|
||||
"original bytearray object and two empty bytearray objects.");
|
||||
|
||||
#define BYTEARRAY_PARTITION_METHODDEF \
|
||||
{"partition", (PyCFunction)bytearray_partition, METH_O, bytearray_partition__doc__},
|
||||
|
||||
PyDoc_STRVAR(bytearray_rpartition__doc__,
|
||||
"rpartition($self, sep, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Partition the bytearray into three parts using the given separator.\n"
|
||||
"\n"
|
||||
"This will search for the separator sep in the bytearray, starting at the end.\n"
|
||||
"If the separator is found, returns a 3-tuple containing the part before the\n"
|
||||
"separator, the separator itself, and the part after it as new bytearray\n"
|
||||
"objects.\n"
|
||||
"\n"
|
||||
"If the separator is not found, returns a 3-tuple containing two empty bytearray\n"
|
||||
"objects and the copy of the original bytearray object.");
|
||||
|
||||
#define BYTEARRAY_RPARTITION_METHODDEF \
|
||||
{"rpartition", (PyCFunction)bytearray_rpartition, METH_O, bytearray_rpartition__doc__},
|
||||
|
||||
PyDoc_STRVAR(bytearray_rsplit__doc__,
|
||||
"rsplit($self, /, sep=None, maxsplit=-1)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a list of the sections in the bytearray, using sep as the delimiter.\n"
|
||||
"\n"
|
||||
" sep\n"
|
||||
" The delimiter according which to split the bytearray.\n"
|
||||
" None (the default value) means split on ASCII whitespace characters\n"
|
||||
" (space, tab, return, newline, formfeed, vertical tab).\n"
|
||||
" maxsplit\n"
|
||||
" Maximum number of splits to do.\n"
|
||||
" -1 (the default value) means no limit.\n"
|
||||
"\n"
|
||||
"Splitting is done starting at the end of the bytearray and working to the front.");
|
||||
|
||||
#define BYTEARRAY_RSPLIT_METHODDEF \
|
||||
{"rsplit", (PyCFunction)bytearray_rsplit, METH_FASTCALL, bytearray_rsplit__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_rsplit_impl(PyByteArrayObject *self, PyObject *sep,
|
||||
Py_ssize_t maxsplit);
|
||||
|
||||
static PyObject *
|
||||
bytearray_rsplit(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
static const char * const _keywords[] = {"sep", "maxsplit", NULL};
|
||||
static _PyArg_Parser _parser = {"|On:rsplit", _keywords, 0};
|
||||
PyObject *sep = Py_None;
|
||||
Py_ssize_t maxsplit = -1;
|
||||
|
||||
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
|
||||
&sep, &maxsplit)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytearray_rsplit_impl(self, sep, maxsplit);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_reverse__doc__,
|
||||
"reverse($self, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Reverse the order of the values in B in place.");
|
||||
|
||||
#define BYTEARRAY_REVERSE_METHODDEF \
|
||||
{"reverse", (PyCFunction)bytearray_reverse, METH_NOARGS, bytearray_reverse__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_reverse_impl(PyByteArrayObject *self);
|
||||
|
||||
static PyObject *
|
||||
bytearray_reverse(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return bytearray_reverse_impl(self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_insert__doc__,
|
||||
"insert($self, index, item, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Insert a single item into the bytearray before the given index.\n"
|
||||
"\n"
|
||||
" index\n"
|
||||
" The index where the value is to be inserted.\n"
|
||||
" item\n"
|
||||
" The item to be inserted.");
|
||||
|
||||
#define BYTEARRAY_INSERT_METHODDEF \
|
||||
{"insert", (PyCFunction)bytearray_insert, METH_VARARGS, bytearray_insert__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_insert_impl(PyByteArrayObject *self, Py_ssize_t index, int item);
|
||||
|
||||
static PyObject *
|
||||
bytearray_insert(PyByteArrayObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
Py_ssize_t index;
|
||||
int item;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "nO&:insert",
|
||||
&index, _getbytevalue, &item)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytearray_insert_impl(self, index, item);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_append__doc__,
|
||||
"append($self, item, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Append a single item to the end of the bytearray.\n"
|
||||
"\n"
|
||||
" item\n"
|
||||
" The item to be appended.");
|
||||
|
||||
#define BYTEARRAY_APPEND_METHODDEF \
|
||||
{"append", (PyCFunction)bytearray_append, METH_O, bytearray_append__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_append_impl(PyByteArrayObject *self, int item);
|
||||
|
||||
static PyObject *
|
||||
bytearray_append(PyByteArrayObject *self, PyObject *arg)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
int item;
|
||||
|
||||
if (!PyArg_Parse(arg, "O&:append", _getbytevalue, &item)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytearray_append_impl(self, item);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_extend__doc__,
|
||||
"extend($self, iterable_of_ints, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Append all the items from the iterator or sequence to the end of the bytearray.\n"
|
||||
"\n"
|
||||
" iterable_of_ints\n"
|
||||
" The iterable of items to append.");
|
||||
|
||||
#define BYTEARRAY_EXTEND_METHODDEF \
|
||||
{"extend", (PyCFunction)bytearray_extend, METH_O, bytearray_extend__doc__},
|
||||
|
||||
PyDoc_STRVAR(bytearray_pop__doc__,
|
||||
"pop($self, index=-1, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Remove and return a single item from B.\n"
|
||||
"\n"
|
||||
" index\n"
|
||||
" The index from where to remove the item.\n"
|
||||
" -1 (the default value) means remove the last item.\n"
|
||||
"\n"
|
||||
"If no index argument is given, will pop the last item.");
|
||||
|
||||
#define BYTEARRAY_POP_METHODDEF \
|
||||
{"pop", (PyCFunction)bytearray_pop, METH_VARARGS, bytearray_pop__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_pop_impl(PyByteArrayObject *self, Py_ssize_t index);
|
||||
|
||||
static PyObject *
|
||||
bytearray_pop(PyByteArrayObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
Py_ssize_t index = -1;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|n:pop",
|
||||
&index)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytearray_pop_impl(self, index);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_remove__doc__,
|
||||
"remove($self, value, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Remove the first occurrence of a value in the bytearray.\n"
|
||||
"\n"
|
||||
" value\n"
|
||||
" The value to remove.");
|
||||
|
||||
#define BYTEARRAY_REMOVE_METHODDEF \
|
||||
{"remove", (PyCFunction)bytearray_remove, METH_O, bytearray_remove__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_remove_impl(PyByteArrayObject *self, int value);
|
||||
|
||||
static PyObject *
|
||||
bytearray_remove(PyByteArrayObject *self, PyObject *arg)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
int value;
|
||||
|
||||
if (!PyArg_Parse(arg, "O&:remove", _getbytevalue, &value)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytearray_remove_impl(self, value);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_strip__doc__,
|
||||
"strip($self, bytes=None, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Strip leading and trailing bytes contained in the argument.\n"
|
||||
"\n"
|
||||
"If the argument is omitted or None, strip leading and trailing ASCII whitespace.");
|
||||
|
||||
#define BYTEARRAY_STRIP_METHODDEF \
|
||||
{"strip", (PyCFunction)bytearray_strip, METH_VARARGS, bytearray_strip__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_strip_impl(PyByteArrayObject *self, PyObject *bytes);
|
||||
|
||||
static PyObject *
|
||||
bytearray_strip(PyByteArrayObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
PyObject *bytes = Py_None;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "strip",
|
||||
0, 1,
|
||||
&bytes)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytearray_strip_impl(self, bytes);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_lstrip__doc__,
|
||||
"lstrip($self, bytes=None, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Strip leading bytes contained in the argument.\n"
|
||||
"\n"
|
||||
"If the argument is omitted or None, strip leading ASCII whitespace.");
|
||||
|
||||
#define BYTEARRAY_LSTRIP_METHODDEF \
|
||||
{"lstrip", (PyCFunction)bytearray_lstrip, METH_VARARGS, bytearray_lstrip__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_lstrip_impl(PyByteArrayObject *self, PyObject *bytes);
|
||||
|
||||
static PyObject *
|
||||
bytearray_lstrip(PyByteArrayObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
PyObject *bytes = Py_None;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "lstrip",
|
||||
0, 1,
|
||||
&bytes)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytearray_lstrip_impl(self, bytes);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_rstrip__doc__,
|
||||
"rstrip($self, bytes=None, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Strip trailing bytes contained in the argument.\n"
|
||||
"\n"
|
||||
"If the argument is omitted or None, strip trailing ASCII whitespace.");
|
||||
|
||||
#define BYTEARRAY_RSTRIP_METHODDEF \
|
||||
{"rstrip", (PyCFunction)bytearray_rstrip, METH_VARARGS, bytearray_rstrip__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_rstrip_impl(PyByteArrayObject *self, PyObject *bytes);
|
||||
|
||||
static PyObject *
|
||||
bytearray_rstrip(PyByteArrayObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
PyObject *bytes = Py_None;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "rstrip",
|
||||
0, 1,
|
||||
&bytes)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytearray_rstrip_impl(self, bytes);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_decode__doc__,
|
||||
"decode($self, /, encoding=\'utf-8\', errors=\'strict\')\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Decode the bytearray using the codec registered for encoding.\n"
|
||||
"\n"
|
||||
" encoding\n"
|
||||
" The encoding with which to decode the bytearray.\n"
|
||||
" errors\n"
|
||||
" The error handling scheme to use for the handling of decoding errors.\n"
|
||||
" The default is \'strict\' meaning that decoding errors raise a\n"
|
||||
" UnicodeDecodeError. Other possible values are \'ignore\' and \'replace\'\n"
|
||||
" as well as any other name registered with codecs.register_error that\n"
|
||||
" can handle UnicodeDecodeErrors.");
|
||||
|
||||
#define BYTEARRAY_DECODE_METHODDEF \
|
||||
{"decode", (PyCFunction)bytearray_decode, METH_FASTCALL, bytearray_decode__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_decode_impl(PyByteArrayObject *self, const char *encoding,
|
||||
const char *errors);
|
||||
|
||||
static PyObject *
|
||||
bytearray_decode(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
static const char * const _keywords[] = {"encoding", "errors", NULL};
|
||||
static _PyArg_Parser _parser = {"|ss:decode", _keywords, 0};
|
||||
const char *encoding = NULL;
|
||||
const char *errors = NULL;
|
||||
|
||||
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
|
||||
&encoding, &errors)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytearray_decode_impl(self, encoding, errors);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_join__doc__,
|
||||
"join($self, iterable_of_bytes, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Concatenate any number of bytes/bytearray objects.\n"
|
||||
"\n"
|
||||
"The bytearray whose method is called is inserted in between each pair.\n"
|
||||
"\n"
|
||||
"The result is returned as a new bytearray object.");
|
||||
|
||||
#define BYTEARRAY_JOIN_METHODDEF \
|
||||
{"join", (PyCFunction)bytearray_join, METH_O, bytearray_join__doc__},
|
||||
|
||||
PyDoc_STRVAR(bytearray_splitlines__doc__,
|
||||
"splitlines($self, /, keepends=False)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a list of the lines in the bytearray, breaking at line boundaries.\n"
|
||||
"\n"
|
||||
"Line breaks are not included in the resulting list unless keepends is given and\n"
|
||||
"true.");
|
||||
|
||||
#define BYTEARRAY_SPLITLINES_METHODDEF \
|
||||
{"splitlines", (PyCFunction)bytearray_splitlines, METH_FASTCALL, bytearray_splitlines__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_splitlines_impl(PyByteArrayObject *self, int keepends);
|
||||
|
||||
static PyObject *
|
||||
bytearray_splitlines(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
static const char * const _keywords[] = {"keepends", NULL};
|
||||
static _PyArg_Parser _parser = {"|i:splitlines", _keywords, 0};
|
||||
int keepends = 0;
|
||||
|
||||
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
|
||||
&keepends)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytearray_splitlines_impl(self, keepends);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_fromhex__doc__,
|
||||
"fromhex($type, string, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Create a bytearray object from a string of hexadecimal numbers.\n"
|
||||
"\n"
|
||||
"Spaces between two numbers are accepted.\n"
|
||||
"Example: bytearray.fromhex(\'B9 01EF\') -> bytearray(b\'\\\\xb9\\\\x01\\\\xef\')");
|
||||
|
||||
#define BYTEARRAY_FROMHEX_METHODDEF \
|
||||
{"fromhex", (PyCFunction)bytearray_fromhex, METH_O|METH_CLASS, bytearray_fromhex__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_fromhex_impl(PyTypeObject *type, PyObject *string);
|
||||
|
||||
static PyObject *
|
||||
bytearray_fromhex(PyTypeObject *type, PyObject *arg)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
PyObject *string;
|
||||
|
||||
if (!PyArg_Parse(arg, "U:fromhex", &string)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytearray_fromhex_impl(type, string);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_reduce__doc__,
|
||||
"__reduce__($self, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return state information for pickling.");
|
||||
|
||||
#define BYTEARRAY_REDUCE_METHODDEF \
|
||||
{"__reduce__", (PyCFunction)bytearray_reduce, METH_NOARGS, bytearray_reduce__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_reduce_impl(PyByteArrayObject *self);
|
||||
|
||||
static PyObject *
|
||||
bytearray_reduce(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return bytearray_reduce_impl(self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_reduce_ex__doc__,
|
||||
"__reduce_ex__($self, proto=0, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return state information for pickling.");
|
||||
|
||||
#define BYTEARRAY_REDUCE_EX_METHODDEF \
|
||||
{"__reduce_ex__", (PyCFunction)bytearray_reduce_ex, METH_VARARGS, bytearray_reduce_ex__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_reduce_ex_impl(PyByteArrayObject *self, int proto);
|
||||
|
||||
static PyObject *
|
||||
bytearray_reduce_ex(PyByteArrayObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
int proto = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|i:__reduce_ex__",
|
||||
&proto)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytearray_reduce_ex_impl(self, proto);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytearray_sizeof__doc__,
|
||||
"__sizeof__($self, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Returns the size of the bytearray object in memory, in bytes.");
|
||||
|
||||
#define BYTEARRAY_SIZEOF_METHODDEF \
|
||||
{"__sizeof__", (PyCFunction)bytearray_sizeof, METH_NOARGS, bytearray_sizeof__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytearray_sizeof_impl(PyByteArrayObject *self);
|
||||
|
||||
static PyObject *
|
||||
bytearray_sizeof(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return bytearray_sizeof_impl(self);
|
||||
}
|
||||
/*[clinic end generated code: output=8f022100f059226c input=a9049054013a1b77]*/
|
502
third_party/python/Objects/clinic/bytesobject.c.h
generated
vendored
Normal file
502
third_party/python/Objects/clinic/bytesobject.c.h
generated
vendored
Normal file
|
@ -0,0 +1,502 @@
|
|||
/*[clinic input]
|
||||
preserve
|
||||
[clinic start generated code]*/
|
||||
|
||||
PyDoc_STRVAR(bytes_split__doc__,
|
||||
"split($self, /, sep=None, maxsplit=-1)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a list of the sections in the bytes, using sep as the delimiter.\n"
|
||||
"\n"
|
||||
" sep\n"
|
||||
" The delimiter according which to split the bytes.\n"
|
||||
" None (the default value) means split on ASCII whitespace characters\n"
|
||||
" (space, tab, return, newline, formfeed, vertical tab).\n"
|
||||
" maxsplit\n"
|
||||
" Maximum number of splits to do.\n"
|
||||
" -1 (the default value) means no limit.");
|
||||
|
||||
#define BYTES_SPLIT_METHODDEF \
|
||||
{"split", (PyCFunction)bytes_split, METH_FASTCALL, bytes_split__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytes_split_impl(PyBytesObject *self, PyObject *sep, Py_ssize_t maxsplit);
|
||||
|
||||
static PyObject *
|
||||
bytes_split(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
static const char * const _keywords[] = {"sep", "maxsplit", NULL};
|
||||
static _PyArg_Parser _parser = {"|On:split", _keywords, 0};
|
||||
PyObject *sep = Py_None;
|
||||
Py_ssize_t maxsplit = -1;
|
||||
|
||||
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
|
||||
&sep, &maxsplit)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytes_split_impl(self, sep, maxsplit);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytes_partition__doc__,
|
||||
"partition($self, sep, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Partition the bytes into three parts using the given separator.\n"
|
||||
"\n"
|
||||
"This will search for the separator sep in the bytes. If the separator is found,\n"
|
||||
"returns a 3-tuple containing the part before the separator, the separator\n"
|
||||
"itself, and the part after it.\n"
|
||||
"\n"
|
||||
"If the separator is not found, returns a 3-tuple containing the original bytes\n"
|
||||
"object and two empty bytes objects.");
|
||||
|
||||
#define BYTES_PARTITION_METHODDEF \
|
||||
{"partition", (PyCFunction)bytes_partition, METH_O, bytes_partition__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytes_partition_impl(PyBytesObject *self, Py_buffer *sep);
|
||||
|
||||
static PyObject *
|
||||
bytes_partition(PyBytesObject *self, PyObject *arg)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
Py_buffer sep = {NULL, NULL};
|
||||
|
||||
if (!PyArg_Parse(arg, "y*:partition", &sep)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytes_partition_impl(self, &sep);
|
||||
|
||||
exit:
|
||||
/* Cleanup for sep */
|
||||
if (sep.obj) {
|
||||
PyBuffer_Release(&sep);
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytes_rpartition__doc__,
|
||||
"rpartition($self, sep, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Partition the bytes into three parts using the given separator.\n"
|
||||
"\n"
|
||||
"This will search for the separator sep in the bytes, starting at the end. If\n"
|
||||
"the separator is found, returns a 3-tuple containing the part before the\n"
|
||||
"separator, the separator itself, and the part after it.\n"
|
||||
"\n"
|
||||
"If the separator is not found, returns a 3-tuple containing two empty bytes\n"
|
||||
"objects and the original bytes object.");
|
||||
|
||||
#define BYTES_RPARTITION_METHODDEF \
|
||||
{"rpartition", (PyCFunction)bytes_rpartition, METH_O, bytes_rpartition__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytes_rpartition_impl(PyBytesObject *self, Py_buffer *sep);
|
||||
|
||||
static PyObject *
|
||||
bytes_rpartition(PyBytesObject *self, PyObject *arg)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
Py_buffer sep = {NULL, NULL};
|
||||
|
||||
if (!PyArg_Parse(arg, "y*:rpartition", &sep)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytes_rpartition_impl(self, &sep);
|
||||
|
||||
exit:
|
||||
/* Cleanup for sep */
|
||||
if (sep.obj) {
|
||||
PyBuffer_Release(&sep);
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytes_rsplit__doc__,
|
||||
"rsplit($self, /, sep=None, maxsplit=-1)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a list of the sections in the bytes, using sep as the delimiter.\n"
|
||||
"\n"
|
||||
" sep\n"
|
||||
" The delimiter according which to split the bytes.\n"
|
||||
" None (the default value) means split on ASCII whitespace characters\n"
|
||||
" (space, tab, return, newline, formfeed, vertical tab).\n"
|
||||
" maxsplit\n"
|
||||
" Maximum number of splits to do.\n"
|
||||
" -1 (the default value) means no limit.\n"
|
||||
"\n"
|
||||
"Splitting is done starting at the end of the bytes and working to the front.");
|
||||
|
||||
#define BYTES_RSPLIT_METHODDEF \
|
||||
{"rsplit", (PyCFunction)bytes_rsplit, METH_FASTCALL, bytes_rsplit__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytes_rsplit_impl(PyBytesObject *self, PyObject *sep, Py_ssize_t maxsplit);
|
||||
|
||||
static PyObject *
|
||||
bytes_rsplit(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
static const char * const _keywords[] = {"sep", "maxsplit", NULL};
|
||||
static _PyArg_Parser _parser = {"|On:rsplit", _keywords, 0};
|
||||
PyObject *sep = Py_None;
|
||||
Py_ssize_t maxsplit = -1;
|
||||
|
||||
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
|
||||
&sep, &maxsplit)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytes_rsplit_impl(self, sep, maxsplit);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytes_join__doc__,
|
||||
"join($self, iterable_of_bytes, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Concatenate any number of bytes objects.\n"
|
||||
"\n"
|
||||
"The bytes whose method is called is inserted in between each pair.\n"
|
||||
"\n"
|
||||
"The result is returned as a new bytes object.\n"
|
||||
"\n"
|
||||
"Example: b\'.\'.join([b\'ab\', b\'pq\', b\'rs\']) -> b\'ab.pq.rs\'.");
|
||||
|
||||
#define BYTES_JOIN_METHODDEF \
|
||||
{"join", (PyCFunction)bytes_join, METH_O, bytes_join__doc__},
|
||||
|
||||
PyDoc_STRVAR(bytes_strip__doc__,
|
||||
"strip($self, bytes=None, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Strip leading and trailing bytes contained in the argument.\n"
|
||||
"\n"
|
||||
"If the argument is omitted or None, strip leading and trailing ASCII whitespace.");
|
||||
|
||||
#define BYTES_STRIP_METHODDEF \
|
||||
{"strip", (PyCFunction)bytes_strip, METH_VARARGS, bytes_strip__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytes_strip_impl(PyBytesObject *self, PyObject *bytes);
|
||||
|
||||
static PyObject *
|
||||
bytes_strip(PyBytesObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
PyObject *bytes = Py_None;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "strip",
|
||||
0, 1,
|
||||
&bytes)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytes_strip_impl(self, bytes);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytes_lstrip__doc__,
|
||||
"lstrip($self, bytes=None, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Strip leading bytes contained in the argument.\n"
|
||||
"\n"
|
||||
"If the argument is omitted or None, strip leading ASCII whitespace.");
|
||||
|
||||
#define BYTES_LSTRIP_METHODDEF \
|
||||
{"lstrip", (PyCFunction)bytes_lstrip, METH_VARARGS, bytes_lstrip__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytes_lstrip_impl(PyBytesObject *self, PyObject *bytes);
|
||||
|
||||
static PyObject *
|
||||
bytes_lstrip(PyBytesObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
PyObject *bytes = Py_None;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "lstrip",
|
||||
0, 1,
|
||||
&bytes)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytes_lstrip_impl(self, bytes);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytes_rstrip__doc__,
|
||||
"rstrip($self, bytes=None, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Strip trailing bytes contained in the argument.\n"
|
||||
"\n"
|
||||
"If the argument is omitted or None, strip trailing ASCII whitespace.");
|
||||
|
||||
#define BYTES_RSTRIP_METHODDEF \
|
||||
{"rstrip", (PyCFunction)bytes_rstrip, METH_VARARGS, bytes_rstrip__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytes_rstrip_impl(PyBytesObject *self, PyObject *bytes);
|
||||
|
||||
static PyObject *
|
||||
bytes_rstrip(PyBytesObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
PyObject *bytes = Py_None;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "rstrip",
|
||||
0, 1,
|
||||
&bytes)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytes_rstrip_impl(self, bytes);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytes_translate__doc__,
|
||||
"translate($self, table, /, delete=b\'\')\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a copy with each character mapped by the given translation table.\n"
|
||||
"\n"
|
||||
" table\n"
|
||||
" Translation table, which must be a bytes object of length 256.\n"
|
||||
"\n"
|
||||
"All characters occurring in the optional argument delete are removed.\n"
|
||||
"The remaining characters are mapped through the given translation table.");
|
||||
|
||||
#define BYTES_TRANSLATE_METHODDEF \
|
||||
{"translate", (PyCFunction)bytes_translate, METH_FASTCALL, bytes_translate__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytes_translate_impl(PyBytesObject *self, PyObject *table,
|
||||
PyObject *deletechars);
|
||||
|
||||
static PyObject *
|
||||
bytes_translate(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
static const char * const _keywords[] = {"", "delete", NULL};
|
||||
static _PyArg_Parser _parser = {"O|O:translate", _keywords, 0};
|
||||
PyObject *table;
|
||||
PyObject *deletechars = NULL;
|
||||
|
||||
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
|
||||
&table, &deletechars)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytes_translate_impl(self, table, deletechars);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytes_maketrans__doc__,
|
||||
"maketrans(frm, to, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a translation table useable for the bytes or bytearray translate method.\n"
|
||||
"\n"
|
||||
"The returned table will be one where each byte in frm is mapped to the byte at\n"
|
||||
"the same position in to.\n"
|
||||
"\n"
|
||||
"The bytes objects frm and to must be of the same length.");
|
||||
|
||||
#define BYTES_MAKETRANS_METHODDEF \
|
||||
{"maketrans", (PyCFunction)bytes_maketrans, METH_VARARGS|METH_STATIC, bytes_maketrans__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytes_maketrans_impl(Py_buffer *frm, Py_buffer *to);
|
||||
|
||||
static PyObject *
|
||||
bytes_maketrans(void *null, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
Py_buffer frm = {NULL, NULL};
|
||||
Py_buffer to = {NULL, NULL};
|
||||
|
||||
if (!PyArg_ParseTuple(args, "y*y*:maketrans",
|
||||
&frm, &to)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytes_maketrans_impl(&frm, &to);
|
||||
|
||||
exit:
|
||||
/* Cleanup for frm */
|
||||
if (frm.obj) {
|
||||
PyBuffer_Release(&frm);
|
||||
}
|
||||
/* Cleanup for to */
|
||||
if (to.obj) {
|
||||
PyBuffer_Release(&to);
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytes_replace__doc__,
|
||||
"replace($self, old, new, count=-1, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a copy with all occurrences of substring old replaced by new.\n"
|
||||
"\n"
|
||||
" count\n"
|
||||
" Maximum number of occurrences to replace.\n"
|
||||
" -1 (the default value) means replace all occurrences.\n"
|
||||
"\n"
|
||||
"If the optional argument count is given, only the first count occurrences are\n"
|
||||
"replaced.");
|
||||
|
||||
#define BYTES_REPLACE_METHODDEF \
|
||||
{"replace", (PyCFunction)bytes_replace, METH_VARARGS, bytes_replace__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytes_replace_impl(PyBytesObject *self, Py_buffer *old, Py_buffer *new,
|
||||
Py_ssize_t count);
|
||||
|
||||
static PyObject *
|
||||
bytes_replace(PyBytesObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
Py_buffer old = {NULL, NULL};
|
||||
Py_buffer new = {NULL, NULL};
|
||||
Py_ssize_t count = -1;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "y*y*|n:replace",
|
||||
&old, &new, &count)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytes_replace_impl(self, &old, &new, count);
|
||||
|
||||
exit:
|
||||
/* Cleanup for old */
|
||||
if (old.obj) {
|
||||
PyBuffer_Release(&old);
|
||||
}
|
||||
/* Cleanup for new */
|
||||
if (new.obj) {
|
||||
PyBuffer_Release(&new);
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytes_decode__doc__,
|
||||
"decode($self, /, encoding=\'utf-8\', errors=\'strict\')\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Decode the bytes using the codec registered for encoding.\n"
|
||||
"\n"
|
||||
" encoding\n"
|
||||
" The encoding with which to decode the bytes.\n"
|
||||
" errors\n"
|
||||
" The error handling scheme to use for the handling of decoding errors.\n"
|
||||
" The default is \'strict\' meaning that decoding errors raise a\n"
|
||||
" UnicodeDecodeError. Other possible values are \'ignore\' and \'replace\'\n"
|
||||
" as well as any other name registered with codecs.register_error that\n"
|
||||
" can handle UnicodeDecodeErrors.");
|
||||
|
||||
#define BYTES_DECODE_METHODDEF \
|
||||
{"decode", (PyCFunction)bytes_decode, METH_FASTCALL, bytes_decode__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytes_decode_impl(PyBytesObject *self, const char *encoding,
|
||||
const char *errors);
|
||||
|
||||
static PyObject *
|
||||
bytes_decode(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
static const char * const _keywords[] = {"encoding", "errors", NULL};
|
||||
static _PyArg_Parser _parser = {"|ss:decode", _keywords, 0};
|
||||
const char *encoding = NULL;
|
||||
const char *errors = NULL;
|
||||
|
||||
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
|
||||
&encoding, &errors)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytes_decode_impl(self, encoding, errors);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytes_splitlines__doc__,
|
||||
"splitlines($self, /, keepends=False)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a list of the lines in the bytes, breaking at line boundaries.\n"
|
||||
"\n"
|
||||
"Line breaks are not included in the resulting list unless keepends is given and\n"
|
||||
"true.");
|
||||
|
||||
#define BYTES_SPLITLINES_METHODDEF \
|
||||
{"splitlines", (PyCFunction)bytes_splitlines, METH_FASTCALL, bytes_splitlines__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytes_splitlines_impl(PyBytesObject *self, int keepends);
|
||||
|
||||
static PyObject *
|
||||
bytes_splitlines(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
static const char * const _keywords[] = {"keepends", NULL};
|
||||
static _PyArg_Parser _parser = {"|i:splitlines", _keywords, 0};
|
||||
int keepends = 0;
|
||||
|
||||
if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser,
|
||||
&keepends)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytes_splitlines_impl(self, keepends);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(bytes_fromhex__doc__,
|
||||
"fromhex($type, string, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Create a bytes object from a string of hexadecimal numbers.\n"
|
||||
"\n"
|
||||
"Spaces between two numbers are accepted.\n"
|
||||
"Example: bytes.fromhex(\'B9 01EF\') -> b\'\\\\xb9\\\\x01\\\\xef\'.");
|
||||
|
||||
#define BYTES_FROMHEX_METHODDEF \
|
||||
{"fromhex", (PyCFunction)bytes_fromhex, METH_O|METH_CLASS, bytes_fromhex__doc__},
|
||||
|
||||
static PyObject *
|
||||
bytes_fromhex_impl(PyTypeObject *type, PyObject *string);
|
||||
|
||||
static PyObject *
|
||||
bytes_fromhex(PyTypeObject *type, PyObject *arg)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
PyObject *string;
|
||||
|
||||
if (!PyArg_Parse(arg, "U:fromhex", &string)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = bytes_fromhex_impl(type, string);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
/*[clinic end generated code: output=4ac7e35150d47467 input=a9049054013a1b77]*/
|
43
third_party/python/Objects/clinic/dictobject.c.h
generated
vendored
Normal file
43
third_party/python/Objects/clinic/dictobject.c.h
generated
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*[clinic input]
|
||||
preserve
|
||||
[clinic start generated code]*/
|
||||
|
||||
PyDoc_STRVAR(dict_fromkeys__doc__,
|
||||
"fromkeys($type, iterable, value=None, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Returns a new dict with keys from iterable and values equal to value.");
|
||||
|
||||
#define DICT_FROMKEYS_METHODDEF \
|
||||
{"fromkeys", (PyCFunction)dict_fromkeys, METH_VARARGS|METH_CLASS, dict_fromkeys__doc__},
|
||||
|
||||
static PyObject *
|
||||
dict_fromkeys_impl(PyTypeObject *type, PyObject *iterable, PyObject *value);
|
||||
|
||||
static PyObject *
|
||||
dict_fromkeys(PyTypeObject *type, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
PyObject *iterable;
|
||||
PyObject *value = Py_None;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "fromkeys",
|
||||
1, 2,
|
||||
&iterable, &value)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = dict_fromkeys_impl(type, iterable, value);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(dict___contains____doc__,
|
||||
"__contains__($self, key, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"True if D has a key k, else False.");
|
||||
|
||||
#define DICT___CONTAINS___METHODDEF \
|
||||
{"__contains__", (PyCFunction)dict___contains__, METH_O|METH_COEXIST, dict___contains____doc__},
|
||||
/*[clinic end generated code: output=926326109e3d9839 input=a9049054013a1b77]*/
|
42
third_party/python/Objects/clinic/unicodeobject.c.h
generated
vendored
Normal file
42
third_party/python/Objects/clinic/unicodeobject.c.h
generated
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*[clinic input]
|
||||
preserve
|
||||
[clinic start generated code]*/
|
||||
|
||||
PyDoc_STRVAR(unicode_maketrans__doc__,
|
||||
"maketrans(x, y=None, z=None, /)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"Return a translation table usable for str.translate().\n"
|
||||
"\n"
|
||||
"If there is only one argument, it must be a dictionary mapping Unicode\n"
|
||||
"ordinals (integers) or characters to Unicode ordinals, strings or None.\n"
|
||||
"Character keys will be then converted to ordinals.\n"
|
||||
"If there are two arguments, they must be strings of equal length, and\n"
|
||||
"in the resulting dictionary, each character in x will be mapped to the\n"
|
||||
"character at the same position in y. If there is a third argument, it\n"
|
||||
"must be a string, whose characters will be mapped to None in the result.");
|
||||
|
||||
#define UNICODE_MAKETRANS_METHODDEF \
|
||||
{"maketrans", (PyCFunction)unicode_maketrans, METH_VARARGS|METH_STATIC, unicode_maketrans__doc__},
|
||||
|
||||
static PyObject *
|
||||
unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z);
|
||||
|
||||
static PyObject *
|
||||
unicode_maketrans(void *null, PyObject *args)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
PyObject *x;
|
||||
PyObject *y = NULL;
|
||||
PyObject *z = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O|UU:maketrans",
|
||||
&x, &y, &z)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = unicode_maketrans_impl(x, y, z);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
/*[clinic end generated code: output=4a86dd108d92d104 input=a9049054013a1b77]*/
|
940
third_party/python/Objects/codeobject.c
vendored
Normal file
940
third_party/python/Objects/codeobject.c
vendored
Normal file
|
@ -0,0 +1,940 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
#include "Python.h"
|
||||
#include "code.h"
|
||||
#include "structmember.h"
|
||||
|
||||
#define NAME_CHARS \
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
/* Holder for co_extra information */
|
||||
typedef struct {
|
||||
Py_ssize_t ce_size;
|
||||
void **ce_extras;
|
||||
} _PyCodeObjectExtra;
|
||||
|
||||
/* all_name_chars(s): true iff all chars in s are valid NAME_CHARS */
|
||||
|
||||
static int
|
||||
all_name_chars(PyObject *o)
|
||||
{
|
||||
static char ok_name_char[256];
|
||||
static const unsigned char *name_chars = (unsigned char *)NAME_CHARS;
|
||||
const unsigned char *s, *e;
|
||||
|
||||
if (!PyUnicode_IS_ASCII(o))
|
||||
return 0;
|
||||
|
||||
if (ok_name_char[*name_chars] == 0) {
|
||||
const unsigned char *p;
|
||||
for (p = name_chars; *p; p++)
|
||||
ok_name_char[*p] = 1;
|
||||
}
|
||||
s = PyUnicode_1BYTE_DATA(o);
|
||||
e = s + PyUnicode_GET_LENGTH(o);
|
||||
while (s != e) {
|
||||
if (ok_name_char[*s++] == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
intern_strings(PyObject *tuple)
|
||||
{
|
||||
Py_ssize_t i;
|
||||
|
||||
for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) {
|
||||
PyObject *v = PyTuple_GET_ITEM(tuple, i);
|
||||
if (v == NULL || !PyUnicode_CheckExact(v)) {
|
||||
Py_FatalError("non-string found in code slot");
|
||||
}
|
||||
PyUnicode_InternInPlace(&PyTuple_GET_ITEM(tuple, i));
|
||||
}
|
||||
}
|
||||
|
||||
/* Intern selected string constants */
|
||||
static int
|
||||
intern_string_constants(PyObject *tuple)
|
||||
{
|
||||
int modified = 0;
|
||||
Py_ssize_t i;
|
||||
|
||||
for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) {
|
||||
PyObject *v = PyTuple_GET_ITEM(tuple, i);
|
||||
if (PyUnicode_CheckExact(v)) {
|
||||
if (PyUnicode_READY(v) == -1) {
|
||||
PyErr_Clear();
|
||||
continue;
|
||||
}
|
||||
if (all_name_chars(v)) {
|
||||
PyObject *w = v;
|
||||
PyUnicode_InternInPlace(&v);
|
||||
if (w != v) {
|
||||
PyTuple_SET_ITEM(tuple, i, v);
|
||||
modified = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (PyTuple_CheckExact(v)) {
|
||||
intern_string_constants(v);
|
||||
}
|
||||
else if (PyFrozenSet_CheckExact(v)) {
|
||||
PyObject *w = v;
|
||||
PyObject *tmp = PySequence_Tuple(v);
|
||||
if (tmp == NULL) {
|
||||
PyErr_Clear();
|
||||
continue;
|
||||
}
|
||||
if (intern_string_constants(tmp)) {
|
||||
v = PyFrozenSet_New(tmp);
|
||||
if (v == NULL) {
|
||||
PyErr_Clear();
|
||||
}
|
||||
else {
|
||||
PyTuple_SET_ITEM(tuple, i, v);
|
||||
Py_DECREF(w);
|
||||
modified = 1;
|
||||
}
|
||||
}
|
||||
Py_DECREF(tmp);
|
||||
}
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
|
||||
PyCodeObject *
|
||||
PyCode_New(int argcount, int kwonlyargcount,
|
||||
int nlocals, int stacksize, int flags,
|
||||
PyObject *code, PyObject *consts, PyObject *names,
|
||||
PyObject *varnames, PyObject *freevars, PyObject *cellvars,
|
||||
PyObject *filename, PyObject *name, int firstlineno,
|
||||
PyObject *lnotab)
|
||||
{
|
||||
PyCodeObject *co;
|
||||
unsigned char *cell2arg = NULL;
|
||||
Py_ssize_t i, n_cellvars, n_varnames, total_args;
|
||||
|
||||
/* Check argument types */
|
||||
if (argcount < 0 || kwonlyargcount < 0 || nlocals < 0 ||
|
||||
code == NULL ||
|
||||
consts == NULL || !PyTuple_Check(consts) ||
|
||||
names == NULL || !PyTuple_Check(names) ||
|
||||
varnames == NULL || !PyTuple_Check(varnames) ||
|
||||
freevars == NULL || !PyTuple_Check(freevars) ||
|
||||
cellvars == NULL || !PyTuple_Check(cellvars) ||
|
||||
name == NULL || !PyUnicode_Check(name) ||
|
||||
filename == NULL || !PyUnicode_Check(filename) ||
|
||||
lnotab == NULL || !PyBytes_Check(lnotab) ||
|
||||
!PyObject_CheckReadBuffer(code)) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Ensure that the filename is a ready Unicode string */
|
||||
if (PyUnicode_READY(filename) < 0)
|
||||
return NULL;
|
||||
|
||||
intern_strings(names);
|
||||
intern_strings(varnames);
|
||||
intern_strings(freevars);
|
||||
intern_strings(cellvars);
|
||||
intern_string_constants(consts);
|
||||
|
||||
/* Check for any inner or outer closure references */
|
||||
n_cellvars = PyTuple_GET_SIZE(cellvars);
|
||||
if (!n_cellvars && !PyTuple_GET_SIZE(freevars)) {
|
||||
flags |= CO_NOFREE;
|
||||
} else {
|
||||
flags &= ~CO_NOFREE;
|
||||
}
|
||||
|
||||
n_varnames = PyTuple_GET_SIZE(varnames);
|
||||
if (argcount <= n_varnames && kwonlyargcount <= n_varnames) {
|
||||
/* Never overflows. */
|
||||
total_args = (Py_ssize_t)argcount + (Py_ssize_t)kwonlyargcount +
|
||||
((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0);
|
||||
}
|
||||
else {
|
||||
total_args = n_varnames + 1;
|
||||
}
|
||||
if (total_args > n_varnames) {
|
||||
PyErr_SetString(PyExc_ValueError, "code: varnames is too small");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create mapping between cells and arguments if needed. */
|
||||
if (n_cellvars) {
|
||||
Py_ssize_t alloc_size = sizeof(unsigned char) * n_cellvars;
|
||||
bool used_cell2arg = false;
|
||||
cell2arg = PyMem_MALLOC(alloc_size);
|
||||
if (cell2arg == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
memset(cell2arg, CO_CELL_NOT_AN_ARG, alloc_size);
|
||||
/* Find cells which are also arguments. */
|
||||
for (i = 0; i < n_cellvars; i++) {
|
||||
Py_ssize_t j;
|
||||
PyObject *cell = PyTuple_GET_ITEM(cellvars, i);
|
||||
for (j = 0; j < total_args; j++) {
|
||||
PyObject *arg = PyTuple_GET_ITEM(varnames, j);
|
||||
int cmp = PyUnicode_Compare(cell, arg);
|
||||
if (cmp == -1 && PyErr_Occurred()) {
|
||||
PyMem_FREE(cell2arg);
|
||||
return NULL;
|
||||
}
|
||||
if (cmp == 0) {
|
||||
cell2arg[i] = j;
|
||||
used_cell2arg = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!used_cell2arg) {
|
||||
PyMem_FREE(cell2arg);
|
||||
cell2arg = NULL;
|
||||
}
|
||||
}
|
||||
co = PyObject_NEW(PyCodeObject, &PyCode_Type);
|
||||
if (co == NULL) {
|
||||
if (cell2arg)
|
||||
PyMem_FREE(cell2arg);
|
||||
return NULL;
|
||||
}
|
||||
co->co_argcount = argcount;
|
||||
co->co_kwonlyargcount = kwonlyargcount;
|
||||
co->co_nlocals = nlocals;
|
||||
co->co_stacksize = stacksize;
|
||||
co->co_flags = flags;
|
||||
Py_INCREF(code);
|
||||
co->co_code = code;
|
||||
Py_INCREF(consts);
|
||||
co->co_consts = consts;
|
||||
Py_INCREF(names);
|
||||
co->co_names = names;
|
||||
Py_INCREF(varnames);
|
||||
co->co_varnames = varnames;
|
||||
Py_INCREF(freevars);
|
||||
co->co_freevars = freevars;
|
||||
Py_INCREF(cellvars);
|
||||
co->co_cellvars = cellvars;
|
||||
co->co_cell2arg = cell2arg;
|
||||
Py_INCREF(filename);
|
||||
co->co_filename = filename;
|
||||
Py_INCREF(name);
|
||||
co->co_name = name;
|
||||
co->co_firstlineno = firstlineno;
|
||||
Py_INCREF(lnotab);
|
||||
co->co_lnotab = lnotab;
|
||||
co->co_zombieframe = NULL;
|
||||
co->co_weakreflist = NULL;
|
||||
co->co_extra = NULL;
|
||||
return co;
|
||||
}
|
||||
|
||||
PyCodeObject *
|
||||
PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
|
||||
{
|
||||
static PyObject *emptystring = NULL;
|
||||
static PyObject *nulltuple = NULL;
|
||||
PyObject *filename_ob = NULL;
|
||||
PyObject *funcname_ob = NULL;
|
||||
PyCodeObject *result = NULL;
|
||||
if (emptystring == NULL) {
|
||||
emptystring = PyBytes_FromString("");
|
||||
if (emptystring == NULL)
|
||||
goto failed;
|
||||
}
|
||||
if (nulltuple == NULL) {
|
||||
nulltuple = PyTuple_New(0);
|
||||
if (nulltuple == NULL)
|
||||
goto failed;
|
||||
}
|
||||
funcname_ob = PyUnicode_FromString(funcname);
|
||||
if (funcname_ob == NULL)
|
||||
goto failed;
|
||||
filename_ob = PyUnicode_DecodeFSDefault(filename);
|
||||
if (filename_ob == NULL)
|
||||
goto failed;
|
||||
|
||||
result = PyCode_New(0, /* argcount */
|
||||
0, /* kwonlyargcount */
|
||||
0, /* nlocals */
|
||||
0, /* stacksize */
|
||||
0, /* flags */
|
||||
emptystring, /* code */
|
||||
nulltuple, /* consts */
|
||||
nulltuple, /* names */
|
||||
nulltuple, /* varnames */
|
||||
nulltuple, /* freevars */
|
||||
nulltuple, /* cellvars */
|
||||
filename_ob, /* filename */
|
||||
funcname_ob, /* name */
|
||||
firstlineno, /* firstlineno */
|
||||
emptystring /* lnotab */
|
||||
);
|
||||
|
||||
failed:
|
||||
Py_XDECREF(funcname_ob);
|
||||
Py_XDECREF(filename_ob);
|
||||
return result;
|
||||
}
|
||||
|
||||
#define OFF(x) offsetof(PyCodeObject, x)
|
||||
|
||||
static PyMemberDef code_memberlist[] = {
|
||||
{"co_argcount", T_INT, OFF(co_argcount), READONLY},
|
||||
{"co_kwonlyargcount", T_INT, OFF(co_kwonlyargcount), READONLY},
|
||||
{"co_nlocals", T_INT, OFF(co_nlocals), READONLY},
|
||||
{"co_stacksize",T_INT, OFF(co_stacksize), READONLY},
|
||||
{"co_flags", T_INT, OFF(co_flags), READONLY},
|
||||
{"co_code", T_OBJECT, OFF(co_code), READONLY},
|
||||
{"co_consts", T_OBJECT, OFF(co_consts), READONLY},
|
||||
{"co_names", T_OBJECT, OFF(co_names), READONLY},
|
||||
{"co_varnames", T_OBJECT, OFF(co_varnames), READONLY},
|
||||
{"co_freevars", T_OBJECT, OFF(co_freevars), READONLY},
|
||||
{"co_cellvars", T_OBJECT, OFF(co_cellvars), READONLY},
|
||||
{"co_filename", T_OBJECT, OFF(co_filename), READONLY},
|
||||
{"co_name", T_OBJECT, OFF(co_name), READONLY},
|
||||
{"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY},
|
||||
{"co_lnotab", T_OBJECT, OFF(co_lnotab), READONLY},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
/* Helper for code_new: return a shallow copy of a tuple that is
|
||||
guaranteed to contain exact strings, by converting string subclasses
|
||||
to exact strings and complaining if a non-string is found. */
|
||||
static PyObject*
|
||||
validate_and_copy_tuple(PyObject *tup)
|
||||
{
|
||||
PyObject *newtuple;
|
||||
PyObject *item;
|
||||
Py_ssize_t i, len;
|
||||
|
||||
len = PyTuple_GET_SIZE(tup);
|
||||
newtuple = PyTuple_New(len);
|
||||
if (newtuple == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
item = PyTuple_GET_ITEM(tup, i);
|
||||
if (PyUnicode_CheckExact(item)) {
|
||||
Py_INCREF(item);
|
||||
}
|
||||
else if (!PyUnicode_Check(item)) {
|
||||
PyErr_Format(
|
||||
PyExc_TypeError,
|
||||
"name tuples must contain only "
|
||||
"strings, not '%.500s'",
|
||||
item->ob_type->tp_name);
|
||||
Py_DECREF(newtuple);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
item = _PyUnicode_Copy(item);
|
||||
if (item == NULL) {
|
||||
Py_DECREF(newtuple);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
PyTuple_SET_ITEM(newtuple, i, item);
|
||||
}
|
||||
|
||||
return newtuple;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(code_doc,
|
||||
"code(argcount, kwonlyargcount, nlocals, stacksize, flags, codestring,\n\
|
||||
constants, names, varnames, filename, name, firstlineno,\n\
|
||||
lnotab[, freevars[, cellvars]])\n\
|
||||
\n\
|
||||
Create a code object. Not for the faint of heart.");
|
||||
|
||||
static PyObject *
|
||||
code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||
{
|
||||
int argcount;
|
||||
int kwonlyargcount;
|
||||
int nlocals;
|
||||
int stacksize;
|
||||
int flags;
|
||||
PyObject *co = NULL;
|
||||
PyObject *code;
|
||||
PyObject *consts;
|
||||
PyObject *names, *ournames = NULL;
|
||||
PyObject *varnames, *ourvarnames = NULL;
|
||||
PyObject *freevars = NULL, *ourfreevars = NULL;
|
||||
PyObject *cellvars = NULL, *ourcellvars = NULL;
|
||||
PyObject *filename;
|
||||
PyObject *name;
|
||||
int firstlineno;
|
||||
PyObject *lnotab;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iiiiiSO!O!O!UUiS|O!O!:code",
|
||||
&argcount, &kwonlyargcount,
|
||||
&nlocals, &stacksize, &flags,
|
||||
&code,
|
||||
&PyTuple_Type, &consts,
|
||||
&PyTuple_Type, &names,
|
||||
&PyTuple_Type, &varnames,
|
||||
&filename, &name,
|
||||
&firstlineno, &lnotab,
|
||||
&PyTuple_Type, &freevars,
|
||||
&PyTuple_Type, &cellvars))
|
||||
return NULL;
|
||||
|
||||
if (argcount < 0) {
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError,
|
||||
"code: argcount must not be negative");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (kwonlyargcount < 0) {
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError,
|
||||
"code: kwonlyargcount must not be negative");
|
||||
goto cleanup;
|
||||
}
|
||||
if (nlocals < 0) {
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError,
|
||||
"code: nlocals must not be negative");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ournames = validate_and_copy_tuple(names);
|
||||
if (ournames == NULL)
|
||||
goto cleanup;
|
||||
ourvarnames = validate_and_copy_tuple(varnames);
|
||||
if (ourvarnames == NULL)
|
||||
goto cleanup;
|
||||
if (freevars)
|
||||
ourfreevars = validate_and_copy_tuple(freevars);
|
||||
else
|
||||
ourfreevars = PyTuple_New(0);
|
||||
if (ourfreevars == NULL)
|
||||
goto cleanup;
|
||||
if (cellvars)
|
||||
ourcellvars = validate_and_copy_tuple(cellvars);
|
||||
else
|
||||
ourcellvars = PyTuple_New(0);
|
||||
if (ourcellvars == NULL)
|
||||
goto cleanup;
|
||||
|
||||
co = (PyObject *)PyCode_New(argcount, kwonlyargcount,
|
||||
nlocals, stacksize, flags,
|
||||
code, consts, ournames, ourvarnames,
|
||||
ourfreevars, ourcellvars, filename,
|
||||
name, firstlineno, lnotab);
|
||||
cleanup:
|
||||
Py_XDECREF(ournames);
|
||||
Py_XDECREF(ourvarnames);
|
||||
Py_XDECREF(ourfreevars);
|
||||
Py_XDECREF(ourcellvars);
|
||||
return co;
|
||||
}
|
||||
|
||||
static void
|
||||
code_dealloc(PyCodeObject *co)
|
||||
{
|
||||
if (co->co_extra != NULL) {
|
||||
__PyCodeExtraState *state = __PyCodeExtraState_Get();
|
||||
_PyCodeObjectExtra *co_extra = co->co_extra;
|
||||
|
||||
for (Py_ssize_t i = 0; i < co_extra->ce_size; i++) {
|
||||
freefunc free_extra = state->co_extra_freefuncs[i];
|
||||
|
||||
if (free_extra != NULL) {
|
||||
free_extra(co_extra->ce_extras[i]);
|
||||
}
|
||||
}
|
||||
|
||||
PyMem_Free(co_extra->ce_extras);
|
||||
PyMem_Free(co_extra);
|
||||
}
|
||||
|
||||
Py_XDECREF(co->co_code);
|
||||
Py_XDECREF(co->co_consts);
|
||||
Py_XDECREF(co->co_names);
|
||||
Py_XDECREF(co->co_varnames);
|
||||
Py_XDECREF(co->co_freevars);
|
||||
Py_XDECREF(co->co_cellvars);
|
||||
Py_XDECREF(co->co_filename);
|
||||
Py_XDECREF(co->co_name);
|
||||
Py_XDECREF(co->co_lnotab);
|
||||
if (co->co_cell2arg != NULL)
|
||||
PyMem_FREE(co->co_cell2arg);
|
||||
if (co->co_zombieframe != NULL)
|
||||
PyObject_GC_Del(co->co_zombieframe);
|
||||
if (co->co_weakreflist != NULL)
|
||||
PyObject_ClearWeakRefs((PyObject*)co);
|
||||
PyObject_DEL(co);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
code_sizeof(PyCodeObject *co, void *unused)
|
||||
{
|
||||
Py_ssize_t res = _PyObject_SIZE(Py_TYPE(co));
|
||||
_PyCodeObjectExtra *co_extra = (_PyCodeObjectExtra*) co->co_extra;
|
||||
|
||||
if (co->co_cell2arg != NULL && co->co_cellvars != NULL)
|
||||
res += PyTuple_GET_SIZE(co->co_cellvars) * sizeof(Py_ssize_t);
|
||||
|
||||
if (co_extra != NULL)
|
||||
res += co_extra->ce_size * sizeof(co_extra->ce_extras[0]);
|
||||
|
||||
return PyLong_FromSsize_t(res);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
code_repr(PyCodeObject *co)
|
||||
{
|
||||
int lineno;
|
||||
if (co->co_firstlineno != 0)
|
||||
lineno = co->co_firstlineno;
|
||||
else
|
||||
lineno = -1;
|
||||
if (co->co_filename && PyUnicode_Check(co->co_filename)) {
|
||||
return PyUnicode_FromFormat(
|
||||
"<code object %U at %p, file \"%U\", line %d>",
|
||||
co->co_name, co, co->co_filename, lineno);
|
||||
} else {
|
||||
return PyUnicode_FromFormat(
|
||||
"<code object %U at %p, file ???, line %d>",
|
||||
co->co_name, co, lineno);
|
||||
}
|
||||
}
|
||||
|
||||
PyObject*
|
||||
_PyCode_ConstantKey(PyObject *op)
|
||||
{
|
||||
PyObject *key;
|
||||
|
||||
/* Py_None and Py_Ellipsis are singleton */
|
||||
if (op == Py_None || op == Py_Ellipsis
|
||||
|| PyLong_CheckExact(op)
|
||||
|| PyBool_Check(op)
|
||||
|| PyBytes_CheckExact(op)
|
||||
|| PyUnicode_CheckExact(op)
|
||||
/* code_richcompare() uses _PyCode_ConstantKey() internally */
|
||||
|| PyCode_Check(op)) {
|
||||
key = PyTuple_Pack(2, Py_TYPE(op), op);
|
||||
}
|
||||
else if (PyFloat_CheckExact(op)) {
|
||||
double d = PyFloat_AS_DOUBLE(op);
|
||||
/* all we need is to make the tuple different in either the 0.0
|
||||
* or -0.0 case from all others, just to avoid the "coercion".
|
||||
*/
|
||||
if (d == 0.0 && copysign(1.0, d) < 0.0)
|
||||
key = PyTuple_Pack(3, Py_TYPE(op), op, Py_None);
|
||||
else
|
||||
key = PyTuple_Pack(2, Py_TYPE(op), op);
|
||||
}
|
||||
else if (PyComplex_CheckExact(op)) {
|
||||
Py_complex z;
|
||||
int real_negzero, imag_negzero;
|
||||
/* For the complex case we must make complex(x, 0.)
|
||||
different from complex(x, -0.) and complex(0., y)
|
||||
different from complex(-0., y), for any x and y.
|
||||
All four complex zeros must be distinguished.*/
|
||||
z = PyComplex_AsCComplex(op);
|
||||
real_negzero = z.real == 0.0 && copysign(1.0, z.real) < 0.0;
|
||||
imag_negzero = z.imag == 0.0 && copysign(1.0, z.imag) < 0.0;
|
||||
/* use True, False and None singleton as tags for the real and imag
|
||||
* sign, to make tuples different */
|
||||
if (real_negzero && imag_negzero) {
|
||||
key = PyTuple_Pack(3, Py_TYPE(op), op, Py_True);
|
||||
}
|
||||
else if (imag_negzero) {
|
||||
key = PyTuple_Pack(3, Py_TYPE(op), op, Py_False);
|
||||
}
|
||||
else if (real_negzero) {
|
||||
key = PyTuple_Pack(3, Py_TYPE(op), op, Py_None);
|
||||
}
|
||||
else {
|
||||
key = PyTuple_Pack(2, Py_TYPE(op), op);
|
||||
}
|
||||
}
|
||||
else if (PyTuple_CheckExact(op)) {
|
||||
Py_ssize_t i, len;
|
||||
PyObject *tuple;
|
||||
|
||||
len = PyTuple_GET_SIZE(op);
|
||||
tuple = PyTuple_New(len);
|
||||
if (tuple == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i=0; i < len; i++) {
|
||||
PyObject *item, *item_key;
|
||||
|
||||
item = PyTuple_GET_ITEM(op, i);
|
||||
item_key = _PyCode_ConstantKey(item);
|
||||
if (item_key == NULL) {
|
||||
Py_DECREF(tuple);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyTuple_SET_ITEM(tuple, i, item_key);
|
||||
}
|
||||
|
||||
key = PyTuple_Pack(2, tuple, op);
|
||||
Py_DECREF(tuple);
|
||||
}
|
||||
else if (PyFrozenSet_CheckExact(op)) {
|
||||
Py_ssize_t pos = 0;
|
||||
PyObject *item;
|
||||
Py_hash_t hash;
|
||||
Py_ssize_t i, len;
|
||||
PyObject *tuple, *set;
|
||||
|
||||
len = PySet_GET_SIZE(op);
|
||||
tuple = PyTuple_New(len);
|
||||
if (tuple == NULL)
|
||||
return NULL;
|
||||
|
||||
i = 0;
|
||||
while (_PySet_NextEntry(op, &pos, &item, &hash)) {
|
||||
PyObject *item_key;
|
||||
|
||||
item_key = _PyCode_ConstantKey(item);
|
||||
if (item_key == NULL) {
|
||||
Py_DECREF(tuple);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(i < len);
|
||||
PyTuple_SET_ITEM(tuple, i, item_key);
|
||||
i++;
|
||||
}
|
||||
set = PyFrozenSet_New(tuple);
|
||||
Py_DECREF(tuple);
|
||||
if (set == NULL)
|
||||
return NULL;
|
||||
|
||||
key = PyTuple_Pack(2, set, op);
|
||||
Py_DECREF(set);
|
||||
return key;
|
||||
}
|
||||
else {
|
||||
/* for other types, use the object identifier as a unique identifier
|
||||
* to ensure that they are seen as unequal. */
|
||||
PyObject *obj_id = PyLong_FromVoidPtr(op);
|
||||
if (obj_id == NULL)
|
||||
return NULL;
|
||||
|
||||
key = PyTuple_Pack(2, obj_id, op);
|
||||
Py_DECREF(obj_id);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
code_richcompare(PyObject *self, PyObject *other, int op)
|
||||
{
|
||||
PyCodeObject *co, *cp;
|
||||
int eq;
|
||||
PyObject *consts1, *consts2;
|
||||
PyObject *res;
|
||||
|
||||
if ((op != Py_EQ && op != Py_NE) ||
|
||||
!PyCode_Check(self) ||
|
||||
!PyCode_Check(other)) {
|
||||
Py_RETURN_NOTIMPLEMENTED;
|
||||
}
|
||||
|
||||
co = (PyCodeObject *)self;
|
||||
cp = (PyCodeObject *)other;
|
||||
|
||||
eq = PyObject_RichCompareBool(co->co_name, cp->co_name, Py_EQ);
|
||||
if (eq <= 0) goto unequal;
|
||||
eq = co->co_argcount == cp->co_argcount;
|
||||
if (!eq) goto unequal;
|
||||
eq = co->co_kwonlyargcount == cp->co_kwonlyargcount;
|
||||
if (!eq) goto unequal;
|
||||
eq = co->co_nlocals == cp->co_nlocals;
|
||||
if (!eq) goto unequal;
|
||||
eq = co->co_flags == cp->co_flags;
|
||||
if (!eq) goto unequal;
|
||||
eq = co->co_firstlineno == cp->co_firstlineno;
|
||||
if (!eq) goto unequal;
|
||||
eq = PyObject_RichCompareBool(co->co_code, cp->co_code, Py_EQ);
|
||||
if (eq <= 0) goto unequal;
|
||||
|
||||
/* compare constants */
|
||||
consts1 = _PyCode_ConstantKey(co->co_consts);
|
||||
if (!consts1)
|
||||
return NULL;
|
||||
consts2 = _PyCode_ConstantKey(cp->co_consts);
|
||||
if (!consts2) {
|
||||
Py_DECREF(consts1);
|
||||
return NULL;
|
||||
}
|
||||
eq = PyObject_RichCompareBool(consts1, consts2, Py_EQ);
|
||||
Py_DECREF(consts1);
|
||||
Py_DECREF(consts2);
|
||||
if (eq <= 0) goto unequal;
|
||||
|
||||
eq = PyObject_RichCompareBool(co->co_names, cp->co_names, Py_EQ);
|
||||
if (eq <= 0) goto unequal;
|
||||
eq = PyObject_RichCompareBool(co->co_varnames, cp->co_varnames, Py_EQ);
|
||||
if (eq <= 0) goto unequal;
|
||||
eq = PyObject_RichCompareBool(co->co_freevars, cp->co_freevars, Py_EQ);
|
||||
if (eq <= 0) goto unequal;
|
||||
eq = PyObject_RichCompareBool(co->co_cellvars, cp->co_cellvars, Py_EQ);
|
||||
if (eq <= 0) goto unequal;
|
||||
|
||||
if (op == Py_EQ)
|
||||
res = Py_True;
|
||||
else
|
||||
res = Py_False;
|
||||
goto done;
|
||||
|
||||
unequal:
|
||||
if (eq < 0)
|
||||
return NULL;
|
||||
if (op == Py_NE)
|
||||
res = Py_True;
|
||||
else
|
||||
res = Py_False;
|
||||
|
||||
done:
|
||||
Py_INCREF(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static Py_hash_t
|
||||
code_hash(PyCodeObject *co)
|
||||
{
|
||||
Py_hash_t h, h0, h1, h2, h3, h4, h5, h6;
|
||||
h0 = PyObject_Hash(co->co_name);
|
||||
if (h0 == -1) return -1;
|
||||
h1 = PyObject_Hash(co->co_code);
|
||||
if (h1 == -1) return -1;
|
||||
h2 = PyObject_Hash(co->co_consts);
|
||||
if (h2 == -1) return -1;
|
||||
h3 = PyObject_Hash(co->co_names);
|
||||
if (h3 == -1) return -1;
|
||||
h4 = PyObject_Hash(co->co_varnames);
|
||||
if (h4 == -1) return -1;
|
||||
h5 = PyObject_Hash(co->co_freevars);
|
||||
if (h5 == -1) return -1;
|
||||
h6 = PyObject_Hash(co->co_cellvars);
|
||||
if (h6 == -1) return -1;
|
||||
h = h0 ^ h1 ^ h2 ^ h3 ^ h4 ^ h5 ^ h6 ^
|
||||
co->co_argcount ^ co->co_kwonlyargcount ^
|
||||
co->co_nlocals ^ co->co_flags;
|
||||
if (h == -1) h = -2;
|
||||
return h;
|
||||
}
|
||||
|
||||
/* XXX code objects need to participate in GC? */
|
||||
|
||||
static struct PyMethodDef code_methods[] = {
|
||||
{"__sizeof__", (PyCFunction)code_sizeof, METH_NOARGS},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
PyTypeObject PyCode_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"code",
|
||||
sizeof(PyCodeObject),
|
||||
0,
|
||||
(destructor)code_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
(reprfunc)code_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
(hashfunc)code_hash, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
code_doc, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
code_richcompare, /* tp_richcompare */
|
||||
offsetof(PyCodeObject, co_weakreflist), /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
code_methods, /* tp_methods */
|
||||
code_memberlist, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
code_new, /* tp_new */
|
||||
};
|
||||
|
||||
/* Use co_lnotab to compute the line number from a bytecode index, addrq. See
|
||||
lnotab_notes.txt for the details of the lnotab representation.
|
||||
*/
|
||||
|
||||
int
|
||||
PyCode_Addr2Line(PyCodeObject *co, int addrq)
|
||||
{
|
||||
Py_ssize_t size = PyBytes_Size(co->co_lnotab) / 2;
|
||||
unsigned char *p = (unsigned char*)PyBytes_AsString(co->co_lnotab);
|
||||
int line = co->co_firstlineno;
|
||||
int addr = 0;
|
||||
while (--size >= 0) {
|
||||
addr += *p++;
|
||||
if (addr > addrq)
|
||||
break;
|
||||
line += (signed char)*p;
|
||||
p++;
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
/* Update *bounds to describe the first and one-past-the-last instructions in
|
||||
the same line as lasti. Return the number of that line. */
|
||||
int
|
||||
_PyCode_CheckLineNumber(PyCodeObject* co, int lasti, PyAddrPair *bounds)
|
||||
{
|
||||
Py_ssize_t size;
|
||||
int addr, line;
|
||||
unsigned char* p;
|
||||
|
||||
p = (unsigned char*)PyBytes_AS_STRING(co->co_lnotab);
|
||||
size = PyBytes_GET_SIZE(co->co_lnotab) / 2;
|
||||
|
||||
addr = 0;
|
||||
line = co->co_firstlineno;
|
||||
assert(line > 0);
|
||||
|
||||
/* possible optimization: if f->f_lasti == instr_ub
|
||||
(likely to be a common case) then we already know
|
||||
instr_lb -- if we stored the matching value of p
|
||||
somewhere we could skip the first while loop. */
|
||||
|
||||
/* See lnotab_notes.txt for the description of
|
||||
co_lnotab. A point to remember: increments to p
|
||||
come in (addr, line) pairs. */
|
||||
|
||||
bounds->ap_lower = 0;
|
||||
while (size > 0) {
|
||||
if (addr + *p > lasti)
|
||||
break;
|
||||
addr += *p++;
|
||||
if ((signed char)*p)
|
||||
bounds->ap_lower = addr;
|
||||
line += (signed char)*p;
|
||||
p++;
|
||||
--size;
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
while (--size >= 0) {
|
||||
addr += *p++;
|
||||
if ((signed char)*p)
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
bounds->ap_upper = addr;
|
||||
}
|
||||
else {
|
||||
bounds->ap_upper = INT_MAX;
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_PyCode_GetExtra(PyObject *code, Py_ssize_t index, void **extra)
|
||||
{
|
||||
if (!PyCode_Check(code)) {
|
||||
PyErr_BadInternalCall();
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyCodeObject *o = (PyCodeObject*) code;
|
||||
_PyCodeObjectExtra *co_extra = (_PyCodeObjectExtra*) o->co_extra;
|
||||
|
||||
|
||||
if (co_extra == NULL || co_extra->ce_size <= index) {
|
||||
*extra = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*extra = co_extra->ce_extras[index];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_PyCode_SetExtra(PyObject *code, Py_ssize_t index, void *extra)
|
||||
{
|
||||
__PyCodeExtraState *state = __PyCodeExtraState_Get();
|
||||
|
||||
if (!PyCode_Check(code) || index < 0 ||
|
||||
index >= state->co_extra_user_count) {
|
||||
PyErr_BadInternalCall();
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyCodeObject *o = (PyCodeObject*) code;
|
||||
_PyCodeObjectExtra *co_extra = (_PyCodeObjectExtra *) o->co_extra;
|
||||
|
||||
if (co_extra == NULL) {
|
||||
co_extra = PyMem_Malloc(sizeof(_PyCodeObjectExtra));
|
||||
if (co_extra == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
co_extra->ce_extras = PyMem_Malloc(
|
||||
state->co_extra_user_count * sizeof(void*));
|
||||
if (co_extra->ce_extras == NULL) {
|
||||
PyMem_Free(co_extra);
|
||||
return -1;
|
||||
}
|
||||
|
||||
co_extra->ce_size = state->co_extra_user_count;
|
||||
|
||||
for (Py_ssize_t i = 0; i < co_extra->ce_size; i++) {
|
||||
co_extra->ce_extras[i] = NULL;
|
||||
}
|
||||
|
||||
o->co_extra = co_extra;
|
||||
}
|
||||
else if (co_extra->ce_size <= index) {
|
||||
void** ce_extras = PyMem_Realloc(
|
||||
co_extra->ce_extras, state->co_extra_user_count * sizeof(void*));
|
||||
|
||||
if (ce_extras == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (Py_ssize_t i = co_extra->ce_size;
|
||||
i < state->co_extra_user_count;
|
||||
i++) {
|
||||
ce_extras[i] = NULL;
|
||||
}
|
||||
|
||||
co_extra->ce_extras = ce_extras;
|
||||
co_extra->ce_size = state->co_extra_user_count;
|
||||
}
|
||||
|
||||
if (co_extra->ce_extras[index] != NULL) {
|
||||
freefunc free = state->co_extra_freefuncs[index];
|
||||
if (free != NULL) {
|
||||
free(co_extra->ce_extras[index]);
|
||||
}
|
||||
}
|
||||
|
||||
co_extra->ce_extras[index] = extra;
|
||||
return 0;
|
||||
}
|
1142
third_party/python/Objects/complexobject.c
vendored
Normal file
1142
third_party/python/Objects/complexobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
1638
third_party/python/Objects/descrobject.c
vendored
Normal file
1638
third_party/python/Objects/descrobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
69
third_party/python/Objects/dict-common.h
vendored
Normal file
69
third_party/python/Objects/dict-common.h
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
#ifndef Py_DICT_COMMON_H
|
||||
#define Py_DICT_COMMON_H
|
||||
|
||||
typedef struct {
|
||||
/* Cached hash code of me_key. */
|
||||
Py_hash_t me_hash;
|
||||
PyObject *me_key;
|
||||
PyObject *me_value; /* This field is only meaningful for combined tables */
|
||||
} PyDictKeyEntry;
|
||||
|
||||
/* dict_lookup_func() returns index of entry which can be used like DK_ENTRIES(dk)[index].
|
||||
* -1 when no entry found, -3 when compare raises error.
|
||||
*/
|
||||
typedef Py_ssize_t (*dict_lookup_func)
|
||||
(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr,
|
||||
Py_ssize_t *hashpos);
|
||||
|
||||
#define DKIX_EMPTY (-1)
|
||||
#define DKIX_DUMMY (-2) /* Used internally */
|
||||
#define DKIX_ERROR (-3)
|
||||
|
||||
/* See dictobject.c for actual layout of DictKeysObject */
|
||||
struct _dictkeysobject {
|
||||
Py_ssize_t dk_refcnt;
|
||||
|
||||
/* Size of the hash table (dk_indices). It must be a power of 2. */
|
||||
Py_ssize_t dk_size;
|
||||
|
||||
/* Function to lookup in the hash table (dk_indices):
|
||||
|
||||
- lookdict(): general-purpose, and may return DKIX_ERROR if (and
|
||||
only if) a comparison raises an exception.
|
||||
|
||||
- lookdict_unicode(): specialized to Unicode string keys, comparison of
|
||||
which can never raise an exception; that function can never return
|
||||
DKIX_ERROR.
|
||||
|
||||
- lookdict_unicode_nodummy(): similar to lookdict_unicode() but further
|
||||
specialized for Unicode string keys that cannot be the <dummy> value.
|
||||
|
||||
- lookdict_split(): Version of lookdict() for split tables. */
|
||||
dict_lookup_func dk_lookup;
|
||||
|
||||
/* Number of usable entries in dk_entries. */
|
||||
Py_ssize_t dk_usable;
|
||||
|
||||
/* Number of used entries in dk_entries. */
|
||||
Py_ssize_t dk_nentries;
|
||||
|
||||
/* Actual hash table of dk_size entries. It holds indices in dk_entries,
|
||||
or DKIX_EMPTY(-1) or DKIX_DUMMY(-2).
|
||||
|
||||
Indices must be: 0 <= indice < USABLE_FRACTION(dk_size).
|
||||
|
||||
The size in bytes of an indice depends on dk_size:
|
||||
|
||||
- 1 byte if dk_size <= 0xff (char*)
|
||||
- 2 bytes if dk_size <= 0xffff (int16_t*)
|
||||
- 4 bytes if dk_size <= 0xffffffff (int32_t*)
|
||||
- 8 bytes otherwise (int64_t*)
|
||||
|
||||
Dynamically sized, SIZEOF_VOID_P is minimum. */
|
||||
char dk_indices[]; /* char is required to avoid strict aliasing. */
|
||||
|
||||
/* "PyDictKeyEntry dk_entries[dk_usable];" array follows:
|
||||
see the DK_ENTRIES() macro */
|
||||
};
|
||||
|
||||
#endif
|
149
third_party/python/Objects/dictnotes.txt
vendored
Normal file
149
third_party/python/Objects/dictnotes.txt
vendored
Normal file
|
@ -0,0 +1,149 @@
|
|||
NOTES ON DICTIONARIES
|
||||
================================
|
||||
|
||||
Principal Use Cases for Dictionaries
|
||||
------------------------------------
|
||||
|
||||
Passing keyword arguments
|
||||
Typically, one read and one write for 1 to 3 elements.
|
||||
Occurs frequently in normal python code.
|
||||
|
||||
Class method lookup
|
||||
Dictionaries vary in size with 8 to 16 elements being common.
|
||||
Usually written once with many lookups.
|
||||
When base classes are used, there are many failed lookups
|
||||
followed by a lookup in a base class.
|
||||
|
||||
Instance attribute lookup and Global variables
|
||||
Dictionaries vary in size. 4 to 10 elements are common.
|
||||
Both reads and writes are common.
|
||||
|
||||
Builtins
|
||||
Frequent reads. Almost never written.
|
||||
About 150 interned strings (as of Py3.3).
|
||||
A few keys are accessed much more frequently than others.
|
||||
|
||||
Uniquification
|
||||
Dictionaries of any size. Bulk of work is in creation.
|
||||
Repeated writes to a smaller set of keys.
|
||||
Single read of each key.
|
||||
Some use cases have two consecutive accesses to the same key.
|
||||
|
||||
* Removing duplicates from a sequence.
|
||||
dict.fromkeys(seqn).keys()
|
||||
|
||||
* Counting elements in a sequence.
|
||||
for e in seqn:
|
||||
d[e] = d.get(e,0) + 1
|
||||
|
||||
* Accumulating references in a dictionary of lists:
|
||||
|
||||
for pagenumber, page in enumerate(pages):
|
||||
for word in page:
|
||||
d.setdefault(word, []).append(pagenumber)
|
||||
|
||||
Note, the second example is a use case characterized by a get and set
|
||||
to the same key. There are similar use cases with a __contains__
|
||||
followed by a get, set, or del to the same key. Part of the
|
||||
justification for d.setdefault is combining the two lookups into one.
|
||||
|
||||
Membership Testing
|
||||
Dictionaries of any size. Created once and then rarely changes.
|
||||
Single write to each key.
|
||||
Many calls to __contains__() or has_key().
|
||||
Similar access patterns occur with replacement dictionaries
|
||||
such as with the % formatting operator.
|
||||
|
||||
Dynamic Mappings
|
||||
Characterized by deletions interspersed with adds and replacements.
|
||||
Performance benefits greatly from the re-use of dummy entries.
|
||||
|
||||
Data Layout
|
||||
-----------
|
||||
|
||||
Dictionaries are composed of 3 components:
|
||||
The dictobject struct itself
|
||||
A dict-keys object (keys & hashes)
|
||||
A values array
|
||||
|
||||
|
||||
Tunable Dictionary Parameters
|
||||
-----------------------------
|
||||
|
||||
See comments for PyDict_MINSIZE_SPLIT, PyDict_MINSIZE_COMBINED,
|
||||
USABLE_FRACTION and GROWTH_RATE in dictobject.c
|
||||
|
||||
Tune-ups should be measured across a broad range of applications and
|
||||
use cases. A change to any parameter will help in some situations and
|
||||
hurt in others. The key is to find settings that help the most common
|
||||
cases and do the least damage to the less common cases. Results will
|
||||
vary dramatically depending on the exact number of keys, whether the
|
||||
keys are all strings, whether reads or writes dominate, the exact
|
||||
hash values of the keys (some sets of values have fewer collisions than
|
||||
others). Any one test or benchmark is likely to prove misleading.
|
||||
|
||||
While making a dictionary more sparse reduces collisions, it impairs
|
||||
iteration and key listing. Those methods loop over every potential
|
||||
entry. Doubling the size of dictionary results in twice as many
|
||||
non-overlapping memory accesses for keys(), items(), values(),
|
||||
__iter__(), iterkeys(), iteritems(), itervalues(), and update().
|
||||
Also, every dictionary iterates at least twice, once for the memset()
|
||||
when it is created and once by dealloc().
|
||||
|
||||
Dictionary operations involving only a single key can be O(1) unless
|
||||
resizing is possible. By checking for a resize only when the
|
||||
dictionary can grow (and may *require* resizing), other operations
|
||||
remain O(1), and the odds of resize thrashing or memory fragmentation
|
||||
are reduced. In particular, an algorithm that empties a dictionary
|
||||
by repeatedly invoking .pop will see no resizing, which might
|
||||
not be necessary at all because the dictionary is eventually
|
||||
discarded entirely.
|
||||
|
||||
The key differences between this implementation and earlier versions are:
|
||||
1. The table can be split into two parts, the keys and the values.
|
||||
|
||||
2. There is an additional key-value combination: (key, NULL).
|
||||
Unlike (<dummy>, NULL) which represents a deleted value, (key, NULL)
|
||||
represented a yet to be inserted value. This combination can only occur
|
||||
when the table is split.
|
||||
|
||||
3. No small table embedded in the dict,
|
||||
as this would make sharing of key-tables impossible.
|
||||
|
||||
|
||||
These changes have the following consequences.
|
||||
1. General dictionaries are slightly larger.
|
||||
|
||||
2. All object dictionaries of a single class can share a single key-table,
|
||||
saving about 60% memory for such cases.
|
||||
|
||||
Results of Cache Locality Experiments
|
||||
--------------------------------------
|
||||
|
||||
Experiments on an earlier design of dictionary, in which all tables were
|
||||
combined, showed the following:
|
||||
|
||||
When an entry is retrieved from memory, several adjacent entries are also
|
||||
retrieved into a cache line. Since accessing items in cache is *much*
|
||||
cheaper than a cache miss, an enticing idea is to probe the adjacent
|
||||
entries as a first step in collision resolution. Unfortunately, the
|
||||
introduction of any regularity into collision searches results in more
|
||||
collisions than the current random chaining approach.
|
||||
|
||||
Exploiting cache locality at the expense of additional collisions fails
|
||||
to payoff when the entries are already loaded in cache (the expense
|
||||
is paid with no compensating benefit). This occurs in small dictionaries
|
||||
where the whole dictionary fits into a pair of cache lines. It also
|
||||
occurs frequently in large dictionaries which have a common access pattern
|
||||
where some keys are accessed much more frequently than others. The
|
||||
more popular entries *and* their collision chains tend to remain in cache.
|
||||
|
||||
To exploit cache locality, change the collision resolution section
|
||||
in lookdict() and lookdict_string(). Set i^=1 at the top of the
|
||||
loop and move the i = (i << 2) + i + perturb + 1 to an unrolled
|
||||
version of the loop.
|
||||
|
||||
For split tables, the above will apply to the keys, but the value will
|
||||
always be in a different cache line from the key.
|
||||
|
||||
|
4472
third_party/python/Objects/dictobject.c
vendored
Normal file
4472
third_party/python/Objects/dictobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
431
third_party/python/Objects/enumobject.c
vendored
Normal file
431
third_party/python/Objects/enumobject.c
vendored
Normal file
|
@ -0,0 +1,431 @@
|
|||
/* enumerate object */
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
Py_ssize_t en_index; /* current index of enumeration */
|
||||
PyObject* en_sit; /* secondary iterator of enumeration */
|
||||
PyObject* en_result; /* result tuple */
|
||||
PyObject* en_longindex; /* index for sequences >= PY_SSIZE_T_MAX */
|
||||
} enumobject;
|
||||
|
||||
static PyObject *
|
||||
enum_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
enumobject *en;
|
||||
PyObject *seq = NULL;
|
||||
PyObject *start = NULL;
|
||||
static char *kwlist[] = {"iterable", "start", 0};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:enumerate", kwlist,
|
||||
&seq, &start))
|
||||
return NULL;
|
||||
|
||||
en = (enumobject *)type->tp_alloc(type, 0);
|
||||
if (en == NULL)
|
||||
return NULL;
|
||||
if (start != NULL) {
|
||||
start = PyNumber_Index(start);
|
||||
if (start == NULL) {
|
||||
Py_DECREF(en);
|
||||
return NULL;
|
||||
}
|
||||
assert(PyLong_Check(start));
|
||||
en->en_index = PyLong_AsSsize_t(start);
|
||||
if (en->en_index == -1 && PyErr_Occurred()) {
|
||||
PyErr_Clear();
|
||||
en->en_index = PY_SSIZE_T_MAX;
|
||||
en->en_longindex = start;
|
||||
} else {
|
||||
en->en_longindex = NULL;
|
||||
Py_DECREF(start);
|
||||
}
|
||||
} else {
|
||||
en->en_index = 0;
|
||||
en->en_longindex = NULL;
|
||||
}
|
||||
en->en_sit = PyObject_GetIter(seq);
|
||||
if (en->en_sit == NULL) {
|
||||
Py_DECREF(en);
|
||||
return NULL;
|
||||
}
|
||||
en->en_result = PyTuple_Pack(2, Py_None, Py_None);
|
||||
if (en->en_result == NULL) {
|
||||
Py_DECREF(en);
|
||||
return NULL;
|
||||
}
|
||||
return (PyObject *)en;
|
||||
}
|
||||
|
||||
static void
|
||||
enum_dealloc(enumobject *en)
|
||||
{
|
||||
PyObject_GC_UnTrack(en);
|
||||
Py_XDECREF(en->en_sit);
|
||||
Py_XDECREF(en->en_result);
|
||||
Py_XDECREF(en->en_longindex);
|
||||
Py_TYPE(en)->tp_free(en);
|
||||
}
|
||||
|
||||
static int
|
||||
enum_traverse(enumobject *en, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(en->en_sit);
|
||||
Py_VISIT(en->en_result);
|
||||
Py_VISIT(en->en_longindex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
enum_next_long(enumobject *en, PyObject* next_item)
|
||||
{
|
||||
static PyObject *one = NULL;
|
||||
PyObject *result = en->en_result;
|
||||
PyObject *next_index;
|
||||
PyObject *stepped_up;
|
||||
|
||||
if (en->en_longindex == NULL) {
|
||||
en->en_longindex = PyLong_FromSsize_t(PY_SSIZE_T_MAX);
|
||||
if (en->en_longindex == NULL) {
|
||||
Py_DECREF(next_item);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (one == NULL) {
|
||||
one = PyLong_FromLong(1);
|
||||
if (one == NULL) {
|
||||
Py_DECREF(next_item);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
next_index = en->en_longindex;
|
||||
assert(next_index != NULL);
|
||||
stepped_up = PyNumber_Add(next_index, one);
|
||||
if (stepped_up == NULL) {
|
||||
Py_DECREF(next_item);
|
||||
return NULL;
|
||||
}
|
||||
en->en_longindex = stepped_up;
|
||||
|
||||
if (result->ob_refcnt == 1) {
|
||||
Py_INCREF(result);
|
||||
Py_DECREF(PyTuple_GET_ITEM(result, 0));
|
||||
Py_DECREF(PyTuple_GET_ITEM(result, 1));
|
||||
} else {
|
||||
result = PyTuple_New(2);
|
||||
if (result == NULL) {
|
||||
Py_DECREF(next_index);
|
||||
Py_DECREF(next_item);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
PyTuple_SET_ITEM(result, 0, next_index);
|
||||
PyTuple_SET_ITEM(result, 1, next_item);
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
enum_next(enumobject *en)
|
||||
{
|
||||
PyObject *next_index;
|
||||
PyObject *next_item;
|
||||
PyObject *result = en->en_result;
|
||||
PyObject *it = en->en_sit;
|
||||
|
||||
next_item = (*Py_TYPE(it)->tp_iternext)(it);
|
||||
if (next_item == NULL)
|
||||
return NULL;
|
||||
|
||||
if (en->en_index == PY_SSIZE_T_MAX)
|
||||
return enum_next_long(en, next_item);
|
||||
|
||||
next_index = PyLong_FromSsize_t(en->en_index);
|
||||
if (next_index == NULL) {
|
||||
Py_DECREF(next_item);
|
||||
return NULL;
|
||||
}
|
||||
en->en_index++;
|
||||
|
||||
if (result->ob_refcnt == 1) {
|
||||
Py_INCREF(result);
|
||||
Py_DECREF(PyTuple_GET_ITEM(result, 0));
|
||||
Py_DECREF(PyTuple_GET_ITEM(result, 1));
|
||||
} else {
|
||||
result = PyTuple_New(2);
|
||||
if (result == NULL) {
|
||||
Py_DECREF(next_index);
|
||||
Py_DECREF(next_item);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
PyTuple_SET_ITEM(result, 0, next_index);
|
||||
PyTuple_SET_ITEM(result, 1, next_item);
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
enum_reduce(enumobject *en)
|
||||
{
|
||||
if (en->en_longindex != NULL)
|
||||
return Py_BuildValue("O(OO)", Py_TYPE(en), en->en_sit, en->en_longindex);
|
||||
else
|
||||
return Py_BuildValue("O(On)", Py_TYPE(en), en->en_sit, en->en_index);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
|
||||
|
||||
static PyMethodDef enum_methods[] = {
|
||||
{"__reduce__", (PyCFunction)enum_reduce, METH_NOARGS, reduce_doc},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(enum_doc,
|
||||
"enumerate(iterable[, start]) -> iterator for index, value of iterable\n"
|
||||
"\n"
|
||||
"Return an enumerate object. iterable must be another object that supports\n"
|
||||
"iteration. The enumerate object yields pairs containing a count (from\n"
|
||||
"start, which defaults to zero) and a value yielded by the iterable argument.\n"
|
||||
"enumerate is useful for obtaining an indexed list:\n"
|
||||
" (0, seq[0]), (1, seq[1]), (2, seq[2]), ...");
|
||||
|
||||
PyTypeObject PyEnum_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"enumerate", /* tp_name */
|
||||
sizeof(enumobject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
/* methods */
|
||||
(destructor)enum_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 | Py_TPFLAGS_HAVE_GC |
|
||||
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
enum_doc, /* tp_doc */
|
||||
(traverseproc)enum_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
PyObject_SelfIter, /* tp_iter */
|
||||
(iternextfunc)enum_next, /* tp_iternext */
|
||||
enum_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
PyType_GenericAlloc, /* tp_alloc */
|
||||
enum_new, /* tp_new */
|
||||
PyObject_GC_Del, /* tp_free */
|
||||
};
|
||||
|
||||
/* Reversed Object ***************************************************************/
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
Py_ssize_t index;
|
||||
PyObject* seq;
|
||||
} reversedobject;
|
||||
|
||||
static PyObject *
|
||||
reversed_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
Py_ssize_t n;
|
||||
PyObject *seq, *reversed_meth;
|
||||
reversedobject *ro;
|
||||
_Py_IDENTIFIER(__reversed__);
|
||||
|
||||
if (type == &PyReversed_Type && !_PyArg_NoKeywords("reversed()", kwds))
|
||||
return NULL;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "reversed", 1, 1, &seq) )
|
||||
return NULL;
|
||||
|
||||
reversed_meth = _PyObject_LookupSpecial(seq, &PyId___reversed__);
|
||||
if (reversed_meth == Py_None) {
|
||||
Py_DECREF(reversed_meth);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"'%.200s' object is not reversible",
|
||||
Py_TYPE(seq)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
if (reversed_meth != NULL) {
|
||||
PyObject *res = PyObject_CallFunctionObjArgs(reversed_meth, NULL);
|
||||
Py_DECREF(reversed_meth);
|
||||
return res;
|
||||
}
|
||||
else if (PyErr_Occurred())
|
||||
return NULL;
|
||||
|
||||
if (!PySequence_Check(seq)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"'%.200s' object is not reversible",
|
||||
Py_TYPE(seq)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n = PySequence_Size(seq);
|
||||
if (n == -1)
|
||||
return NULL;
|
||||
|
||||
ro = (reversedobject *)type->tp_alloc(type, 0);
|
||||
if (ro == NULL)
|
||||
return NULL;
|
||||
|
||||
ro->index = n-1;
|
||||
Py_INCREF(seq);
|
||||
ro->seq = seq;
|
||||
return (PyObject *)ro;
|
||||
}
|
||||
|
||||
static void
|
||||
reversed_dealloc(reversedobject *ro)
|
||||
{
|
||||
PyObject_GC_UnTrack(ro);
|
||||
Py_XDECREF(ro->seq);
|
||||
Py_TYPE(ro)->tp_free(ro);
|
||||
}
|
||||
|
||||
static int
|
||||
reversed_traverse(reversedobject *ro, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(ro->seq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
reversed_next(reversedobject *ro)
|
||||
{
|
||||
PyObject *item;
|
||||
Py_ssize_t index = ro->index;
|
||||
|
||||
if (index >= 0) {
|
||||
item = PySequence_GetItem(ro->seq, index);
|
||||
if (item != NULL) {
|
||||
ro->index--;
|
||||
return item;
|
||||
}
|
||||
if (PyErr_ExceptionMatches(PyExc_IndexError) ||
|
||||
PyErr_ExceptionMatches(PyExc_StopIteration))
|
||||
PyErr_Clear();
|
||||
}
|
||||
ro->index = -1;
|
||||
Py_CLEAR(ro->seq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(reversed_doc,
|
||||
"reversed(sequence) -> reverse iterator over values of the sequence\n"
|
||||
"\n"
|
||||
"Return a reverse iterator");
|
||||
|
||||
static PyObject *
|
||||
reversed_len(reversedobject *ro)
|
||||
{
|
||||
Py_ssize_t position, seqsize;
|
||||
|
||||
if (ro->seq == NULL)
|
||||
return PyLong_FromLong(0);
|
||||
seqsize = PySequence_Size(ro->seq);
|
||||
if (seqsize == -1)
|
||||
return NULL;
|
||||
position = ro->index + 1;
|
||||
return PyLong_FromSsize_t((seqsize < position) ? 0 : position);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
|
||||
|
||||
static PyObject *
|
||||
reversed_reduce(reversedobject *ro)
|
||||
{
|
||||
if (ro->seq)
|
||||
return Py_BuildValue("O(O)n", Py_TYPE(ro), ro->seq, ro->index);
|
||||
else
|
||||
return Py_BuildValue("O(())", Py_TYPE(ro));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
reversed_setstate(reversedobject *ro, PyObject *state)
|
||||
{
|
||||
Py_ssize_t index = PyLong_AsSsize_t(state);
|
||||
if (index == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
if (ro->seq != 0) {
|
||||
Py_ssize_t n = PySequence_Size(ro->seq);
|
||||
if (n < 0)
|
||||
return NULL;
|
||||
if (index < -1)
|
||||
index = -1;
|
||||
else if (index > n-1)
|
||||
index = n-1;
|
||||
ro->index = index;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
|
||||
|
||||
static PyMethodDef reversediter_methods[] = {
|
||||
{"__length_hint__", (PyCFunction)reversed_len, METH_NOARGS, length_hint_doc},
|
||||
{"__reduce__", (PyCFunction)reversed_reduce, METH_NOARGS, reduce_doc},
|
||||
{"__setstate__", (PyCFunction)reversed_setstate, METH_O, setstate_doc},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
PyTypeObject PyReversed_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"reversed", /* tp_name */
|
||||
sizeof(reversedobject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
/* methods */
|
||||
(destructor)reversed_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 | Py_TPFLAGS_HAVE_GC |
|
||||
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
reversed_doc, /* tp_doc */
|
||||
(traverseproc)reversed_traverse,/* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
PyObject_SelfIter, /* tp_iter */
|
||||
(iternextfunc)reversed_next, /* tp_iternext */
|
||||
reversediter_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
PyType_GenericAlloc, /* tp_alloc */
|
||||
reversed_new, /* tp_new */
|
||||
PyObject_GC_Del, /* tp_free */
|
||||
};
|
3012
third_party/python/Objects/exceptions.c
vendored
Normal file
3012
third_party/python/Objects/exceptions.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
531
third_party/python/Objects/fileobject.c
vendored
Normal file
531
third_party/python/Objects/fileobject.c
vendored
Normal file
|
@ -0,0 +1,531 @@
|
|||
/* File object implementation (what's left of it -- see io.py) */
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include "Python.h"
|
||||
|
||||
#if defined(HAVE_GETC_UNLOCKED) && !defined(_Py_MEMORY_SANITIZER)
|
||||
/* clang MemorySanitizer doesn't yet understand getc_unlocked. */
|
||||
#define GETC(f) getc_unlocked(f)
|
||||
#define FLOCKFILE(f) flockfile(f)
|
||||
#define FUNLOCKFILE(f) funlockfile(f)
|
||||
#else
|
||||
#define GETC(f) getc(f)
|
||||
#define FLOCKFILE(f)
|
||||
#define FUNLOCKFILE(f)
|
||||
#endif
|
||||
|
||||
/* Newline flags */
|
||||
#define NEWLINE_UNKNOWN 0 /* No newline seen, yet */
|
||||
#define NEWLINE_CR 1 /* \r newline seen */
|
||||
#define NEWLINE_LF 2 /* \n newline seen */
|
||||
#define NEWLINE_CRLF 4 /* \r\n newline seen */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* External C interface */
|
||||
|
||||
PyObject *
|
||||
PyFile_FromFd(int fd, const char *name, const char *mode, int buffering, const char *encoding,
|
||||
const char *errors, const char *newline, int closefd)
|
||||
{
|
||||
PyObject *io, *stream;
|
||||
_Py_IDENTIFIER(open);
|
||||
|
||||
io = PyImport_ImportModule("io");
|
||||
if (io == NULL)
|
||||
return NULL;
|
||||
stream = _PyObject_CallMethodId(io, &PyId_open, "isisssi", fd, mode,
|
||||
buffering, encoding, errors,
|
||||
newline, closefd);
|
||||
Py_DECREF(io);
|
||||
if (stream == NULL)
|
||||
return NULL;
|
||||
/* ignore name attribute because the name attribute of _BufferedIOMixin
|
||||
and TextIOWrapper is read only */
|
||||
return stream;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyFile_GetLine(PyObject *f, int n)
|
||||
{
|
||||
PyObject *result;
|
||||
|
||||
if (f == NULL) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
{
|
||||
PyObject *reader;
|
||||
PyObject *args;
|
||||
_Py_IDENTIFIER(readline);
|
||||
|
||||
reader = _PyObject_GetAttrId(f, &PyId_readline);
|
||||
if (reader == NULL)
|
||||
return NULL;
|
||||
if (n <= 0)
|
||||
args = PyTuple_New(0);
|
||||
else
|
||||
args = Py_BuildValue("(i)", n);
|
||||
if (args == NULL) {
|
||||
Py_DECREF(reader);
|
||||
return NULL;
|
||||
}
|
||||
result = PyEval_CallObject(reader, args);
|
||||
Py_DECREF(reader);
|
||||
Py_DECREF(args);
|
||||
if (result != NULL && !PyBytes_Check(result) &&
|
||||
!PyUnicode_Check(result)) {
|
||||
Py_DECREF(result);
|
||||
result = NULL;
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"object.readline() returned non-string");
|
||||
}
|
||||
}
|
||||
|
||||
if (n < 0 && result != NULL && PyBytes_Check(result)) {
|
||||
char *s = PyBytes_AS_STRING(result);
|
||||
Py_ssize_t len = PyBytes_GET_SIZE(result);
|
||||
if (len == 0) {
|
||||
Py_DECREF(result);
|
||||
result = NULL;
|
||||
PyErr_SetString(PyExc_EOFError,
|
||||
"EOF when reading a line");
|
||||
}
|
||||
else if (s[len-1] == '\n') {
|
||||
if (result->ob_refcnt == 1)
|
||||
_PyBytes_Resize(&result, len-1);
|
||||
else {
|
||||
PyObject *v;
|
||||
v = PyBytes_FromStringAndSize(s, len-1);
|
||||
Py_DECREF(result);
|
||||
result = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (n < 0 && result != NULL && PyUnicode_Check(result)) {
|
||||
Py_ssize_t len = PyUnicode_GET_LENGTH(result);
|
||||
if (len == 0) {
|
||||
Py_DECREF(result);
|
||||
result = NULL;
|
||||
PyErr_SetString(PyExc_EOFError,
|
||||
"EOF when reading a line");
|
||||
}
|
||||
else if (PyUnicode_READ_CHAR(result, len-1) == '\n') {
|
||||
PyObject *v;
|
||||
v = PyUnicode_Substring(result, 0, len-1);
|
||||
Py_DECREF(result);
|
||||
result = v;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Interfaces to write objects/strings to file-like objects */
|
||||
|
||||
int
|
||||
PyFile_WriteObject(PyObject *v, PyObject *f, int flags)
|
||||
{
|
||||
PyObject *writer, *value, *result;
|
||||
_Py_IDENTIFIER(write);
|
||||
|
||||
if (f == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError, "writeobject with NULL file");
|
||||
return -1;
|
||||
}
|
||||
writer = _PyObject_GetAttrId(f, &PyId_write);
|
||||
if (writer == NULL)
|
||||
return -1;
|
||||
if (flags & Py_PRINT_RAW) {
|
||||
value = PyObject_Str(v);
|
||||
}
|
||||
else
|
||||
value = PyObject_Repr(v);
|
||||
if (value == NULL) {
|
||||
Py_DECREF(writer);
|
||||
return -1;
|
||||
}
|
||||
result = _PyObject_CallArg1(writer, value);
|
||||
Py_DECREF(value);
|
||||
Py_DECREF(writer);
|
||||
if (result == NULL)
|
||||
return -1;
|
||||
Py_DECREF(result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
PyFile_WriteString(const char *s, PyObject *f)
|
||||
{
|
||||
if (f == NULL) {
|
||||
/* Should be caused by a pre-existing error */
|
||||
if (!PyErr_Occurred())
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"null file for PyFile_WriteString");
|
||||
return -1;
|
||||
}
|
||||
else if (!PyErr_Occurred()) {
|
||||
PyObject *v = PyUnicode_FromString(s);
|
||||
int err;
|
||||
if (v == NULL)
|
||||
return -1;
|
||||
err = PyFile_WriteObject(v, f, Py_PRINT_RAW);
|
||||
Py_DECREF(v);
|
||||
return err;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Try to get a file-descriptor from a Python object. If the object
|
||||
is an integer, its value is returned. If not, the
|
||||
object's fileno() method is called if it exists; the method must return
|
||||
an integer, which is returned as the file descriptor value.
|
||||
-1 is returned on failure.
|
||||
*/
|
||||
|
||||
int
|
||||
PyObject_AsFileDescriptor(PyObject *o)
|
||||
{
|
||||
int fd;
|
||||
PyObject *meth;
|
||||
_Py_IDENTIFIER(fileno);
|
||||
|
||||
if (PyLong_Check(o)) {
|
||||
fd = _PyLong_AsInt(o);
|
||||
}
|
||||
else if ((meth = _PyObject_GetAttrId(o, &PyId_fileno)) != NULL)
|
||||
{
|
||||
PyObject *fno = PyEval_CallObject(meth, NULL);
|
||||
Py_DECREF(meth);
|
||||
if (fno == NULL)
|
||||
return -1;
|
||||
|
||||
if (PyLong_Check(fno)) {
|
||||
fd = _PyLong_AsInt(fno);
|
||||
Py_DECREF(fno);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"fileno() returned a non-integer");
|
||||
Py_DECREF(fno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"argument must be an int, or have a fileno() method.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fd == -1 && PyErr_Occurred())
|
||||
return -1;
|
||||
if (fd < 0) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"file descriptor cannot be a negative integer (%i)",
|
||||
fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
** Py_UniversalNewlineFgets is an fgets variation that understands
|
||||
** all of \r, \n and \r\n conventions.
|
||||
** The stream should be opened in binary mode.
|
||||
** If fobj is NULL the routine always does newline conversion, and
|
||||
** it may peek one char ahead to gobble the second char in \r\n.
|
||||
** If fobj is non-NULL it must be a PyFileObject. In this case there
|
||||
** is no readahead but in stead a flag is used to skip a following
|
||||
** \n on the next read. Also, if the file is open in binary mode
|
||||
** the whole conversion is skipped. Finally, the routine keeps track of
|
||||
** the different types of newlines seen.
|
||||
** Note that we need no error handling: fgets() treats error and eof
|
||||
** identically.
|
||||
*/
|
||||
char *
|
||||
Py_UniversalNewlineFgets(char *buf, int n, FILE *stream, PyObject *fobj)
|
||||
{
|
||||
char *p = buf;
|
||||
int c;
|
||||
int newlinetypes = 0;
|
||||
int skipnextlf = 0;
|
||||
|
||||
if (fobj) {
|
||||
errno = ENXIO; /* What can you do... */
|
||||
return NULL;
|
||||
}
|
||||
FLOCKFILE(stream);
|
||||
c = 'x'; /* Shut up gcc warning */
|
||||
while (--n > 0 && (c = GETC(stream)) != EOF ) {
|
||||
if (skipnextlf ) {
|
||||
skipnextlf = 0;
|
||||
if (c == '\n') {
|
||||
/* Seeing a \n here with skipnextlf true
|
||||
** means we saw a \r before.
|
||||
*/
|
||||
newlinetypes |= NEWLINE_CRLF;
|
||||
c = GETC(stream);
|
||||
if (c == EOF) break;
|
||||
} else {
|
||||
/*
|
||||
** Note that c == EOF also brings us here,
|
||||
** so we're okay if the last char in the file
|
||||
** is a CR.
|
||||
*/
|
||||
newlinetypes |= NEWLINE_CR;
|
||||
}
|
||||
}
|
||||
if (c == '\r') {
|
||||
/* A \r is translated into a \n, and we skip
|
||||
** an adjacent \n, if any. We don't set the
|
||||
** newlinetypes flag until we've seen the next char.
|
||||
*/
|
||||
skipnextlf = 1;
|
||||
c = '\n';
|
||||
} else if ( c == '\n') {
|
||||
newlinetypes |= NEWLINE_LF;
|
||||
}
|
||||
*p++ = c;
|
||||
if (c == '\n') break;
|
||||
}
|
||||
/* if ( c == EOF && skipnextlf )
|
||||
newlinetypes |= NEWLINE_CR; */
|
||||
FUNLOCKFILE(stream);
|
||||
*p = '\0';
|
||||
if ( skipnextlf ) {
|
||||
/* If we have no file object we cannot save the
|
||||
** skipnextlf flag. We have to readahead, which
|
||||
** will cause a pause if we're reading from an
|
||||
** interactive stream, but that is very unlikely
|
||||
** unless we're doing something silly like
|
||||
** exec(open("/dev/tty").read()).
|
||||
*/
|
||||
c = GETC(stream);
|
||||
if ( c != '\n' )
|
||||
ungetc(c, stream);
|
||||
}
|
||||
if (p == buf)
|
||||
return NULL;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* **************************** std printer ****************************
|
||||
* The stdprinter is used during the boot strapping phase as a preliminary
|
||||
* file like object for sys.stderr.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
int fd;
|
||||
} PyStdPrinter_Object;
|
||||
|
||||
static PyObject *
|
||||
stdprinter_new(PyTypeObject *type, PyObject *args, PyObject *kews)
|
||||
{
|
||||
PyStdPrinter_Object *self;
|
||||
|
||||
assert(type != NULL && type->tp_alloc != NULL);
|
||||
|
||||
self = (PyStdPrinter_Object *) type->tp_alloc(type, 0);
|
||||
if (self != NULL) {
|
||||
self->fd = -1;
|
||||
}
|
||||
|
||||
return (PyObject *) self;
|
||||
}
|
||||
|
||||
static int
|
||||
stdprinter_init(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"cannot create 'stderrprinter' instances");
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyFile_NewStdPrinter(int fd)
|
||||
{
|
||||
PyStdPrinter_Object *self;
|
||||
|
||||
if (fd != fileno(stdout) && fd != fileno(stderr)) {
|
||||
/* not enough infrastructure for PyErr_BadInternalCall() */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self = PyObject_New(PyStdPrinter_Object,
|
||||
&PyStdPrinter_Type);
|
||||
if (self != NULL) {
|
||||
self->fd = fd;
|
||||
}
|
||||
return (PyObject*)self;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
stdprinter_write(PyStdPrinter_Object *self, PyObject *args)
|
||||
{
|
||||
PyObject *unicode;
|
||||
PyObject *bytes = NULL;
|
||||
char *str;
|
||||
Py_ssize_t n;
|
||||
int err;
|
||||
|
||||
if (self->fd < 0) {
|
||||
/* fd might be invalid on Windows
|
||||
* I can't raise an exception here. It may lead to an
|
||||
* unlimited recursion in the case stderr is invalid.
|
||||
*/
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
if (!PyArg_ParseTuple(args, "U", &unicode))
|
||||
return NULL;
|
||||
|
||||
/* encode Unicode to UTF-8 */
|
||||
str = PyUnicode_AsUTF8AndSize(unicode, &n);
|
||||
if (str == NULL) {
|
||||
PyErr_Clear();
|
||||
bytes = _PyUnicode_AsUTF8String(unicode, "backslashreplace");
|
||||
if (bytes == NULL)
|
||||
return NULL;
|
||||
if (PyBytes_AsStringAndSize(bytes, &str, &n) < 0) {
|
||||
Py_DECREF(bytes);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
n = _Py_write(self->fd, str, n);
|
||||
/* save errno, it can be modified indirectly by Py_XDECREF() */
|
||||
err = errno;
|
||||
|
||||
Py_XDECREF(bytes);
|
||||
|
||||
if (n == -1) {
|
||||
if (err == EAGAIN) {
|
||||
PyErr_Clear();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PyLong_FromSsize_t(n);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
stdprinter_fileno(PyStdPrinter_Object *self)
|
||||
{
|
||||
return PyLong_FromLong((long) self->fd);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
stdprinter_repr(PyStdPrinter_Object *self)
|
||||
{
|
||||
return PyUnicode_FromFormat("<stdprinter(fd=%d) object at 0x%x>",
|
||||
self->fd, self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
stdprinter_noop(PyStdPrinter_Object *self)
|
||||
{
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
stdprinter_isatty(PyStdPrinter_Object *self)
|
||||
{
|
||||
long res;
|
||||
if (self->fd < 0) {
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = isatty(self->fd);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
return PyBool_FromLong(res);
|
||||
}
|
||||
|
||||
static PyMethodDef stdprinter_methods[] = {
|
||||
{"close", (PyCFunction)stdprinter_noop, METH_NOARGS, ""},
|
||||
{"flush", (PyCFunction)stdprinter_noop, METH_NOARGS, ""},
|
||||
{"fileno", (PyCFunction)stdprinter_fileno, METH_NOARGS, ""},
|
||||
{"isatty", (PyCFunction)stdprinter_isatty, METH_NOARGS, ""},
|
||||
{"write", (PyCFunction)stdprinter_write, METH_VARARGS, ""},
|
||||
{NULL, NULL} /*sentinel */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
get_closed(PyStdPrinter_Object *self, void *closure)
|
||||
{
|
||||
Py_INCREF(Py_False);
|
||||
return Py_False;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
get_mode(PyStdPrinter_Object *self, void *closure)
|
||||
{
|
||||
return PyUnicode_FromString("w");
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
get_encoding(PyStdPrinter_Object *self, void *closure)
|
||||
{
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyGetSetDef stdprinter_getsetlist[] = {
|
||||
{"closed", (getter)get_closed, NULL, "True if the file is closed"},
|
||||
{"encoding", (getter)get_encoding, NULL, "Encoding of the file"},
|
||||
{"mode", (getter)get_mode, NULL, "String giving the file mode"},
|
||||
{0},
|
||||
};
|
||||
|
||||
PyTypeObject PyStdPrinter_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"stderrprinter", /* tp_name */
|
||||
sizeof(PyStdPrinter_Object), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
/* methods */
|
||||
0, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
(reprfunc)stdprinter_repr, /* 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 */
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
stdprinter_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
stdprinter_getsetlist, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
stdprinter_init, /* tp_init */
|
||||
PyType_GenericAlloc, /* tp_alloc */
|
||||
stdprinter_new, /* tp_new */
|
||||
PyObject_Del, /* tp_free */
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
2581
third_party/python/Objects/floatobject.c
vendored
Normal file
2581
third_party/python/Objects/floatobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
1039
third_party/python/Objects/frameobject.c
vendored
Normal file
1039
third_party/python/Objects/frameobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
1031
third_party/python/Objects/funcobject.c
vendored
Normal file
1031
third_party/python/Objects/funcobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
2078
third_party/python/Objects/genobject.c
vendored
Normal file
2078
third_party/python/Objects/genobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
287
third_party/python/Objects/iterobject.c
vendored
Normal file
287
third_party/python/Objects/iterobject.c
vendored
Normal file
|
@ -0,0 +1,287 @@
|
|||
/* Iterator objects */
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
Py_ssize_t it_index;
|
||||
PyObject *it_seq; /* Set to NULL when iterator is exhausted */
|
||||
} seqiterobject;
|
||||
|
||||
PyObject *
|
||||
PySeqIter_New(PyObject *seq)
|
||||
{
|
||||
seqiterobject *it;
|
||||
|
||||
if (!PySequence_Check(seq)) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
it = PyObject_GC_New(seqiterobject, &PySeqIter_Type);
|
||||
if (it == NULL)
|
||||
return NULL;
|
||||
it->it_index = 0;
|
||||
Py_INCREF(seq);
|
||||
it->it_seq = seq;
|
||||
_PyObject_GC_TRACK(it);
|
||||
return (PyObject *)it;
|
||||
}
|
||||
|
||||
static void
|
||||
iter_dealloc(seqiterobject *it)
|
||||
{
|
||||
_PyObject_GC_UNTRACK(it);
|
||||
Py_XDECREF(it->it_seq);
|
||||
PyObject_GC_Del(it);
|
||||
}
|
||||
|
||||
static int
|
||||
iter_traverse(seqiterobject *it, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(it->it_seq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
iter_iternext(PyObject *iterator)
|
||||
{
|
||||
seqiterobject *it;
|
||||
PyObject *seq;
|
||||
PyObject *result;
|
||||
|
||||
assert(PySeqIter_Check(iterator));
|
||||
it = (seqiterobject *)iterator;
|
||||
seq = it->it_seq;
|
||||
if (seq == NULL)
|
||||
return NULL;
|
||||
if (it->it_index == PY_SSIZE_T_MAX) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"iter index too large");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = PySequence_GetItem(seq, it->it_index);
|
||||
if (result != NULL) {
|
||||
it->it_index++;
|
||||
return result;
|
||||
}
|
||||
if (PyErr_ExceptionMatches(PyExc_IndexError) ||
|
||||
PyErr_ExceptionMatches(PyExc_StopIteration))
|
||||
{
|
||||
PyErr_Clear();
|
||||
it->it_seq = NULL;
|
||||
Py_DECREF(seq);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
iter_len(seqiterobject *it)
|
||||
{
|
||||
Py_ssize_t seqsize, len;
|
||||
|
||||
if (it->it_seq) {
|
||||
if (_PyObject_HasLen(it->it_seq)) {
|
||||
seqsize = PySequence_Size(it->it_seq);
|
||||
if (seqsize == -1)
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
Py_RETURN_NOTIMPLEMENTED;
|
||||
}
|
||||
len = seqsize - it->it_index;
|
||||
if (len >= 0)
|
||||
return PyLong_FromSsize_t(len);
|
||||
}
|
||||
return PyLong_FromLong(0);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
|
||||
|
||||
static PyObject *
|
||||
iter_reduce(seqiterobject *it)
|
||||
{
|
||||
if (it->it_seq != NULL)
|
||||
return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"),
|
||||
it->it_seq, it->it_index);
|
||||
else
|
||||
return Py_BuildValue("N(())", _PyObject_GetBuiltin("iter"));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
|
||||
|
||||
static PyObject *
|
||||
iter_setstate(seqiterobject *it, PyObject *state)
|
||||
{
|
||||
Py_ssize_t index = PyLong_AsSsize_t(state);
|
||||
if (index == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
if (it->it_seq != NULL) {
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
it->it_index = index;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
|
||||
|
||||
static PyMethodDef seqiter_methods[] = {
|
||||
{"__length_hint__", (PyCFunction)iter_len, METH_NOARGS, length_hint_doc},
|
||||
{"__reduce__", (PyCFunction)iter_reduce, METH_NOARGS, reduce_doc},
|
||||
{"__setstate__", (PyCFunction)iter_setstate, METH_O, setstate_doc},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
PyTypeObject PySeqIter_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"iterator", /* tp_name */
|
||||
sizeof(seqiterobject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
/* methods */
|
||||
(destructor)iter_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 | Py_TPFLAGS_HAVE_GC,/* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc)iter_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
PyObject_SelfIter, /* tp_iter */
|
||||
iter_iternext, /* tp_iternext */
|
||||
seqiter_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
};
|
||||
|
||||
/* -------------------------------------- */
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *it_callable; /* Set to NULL when iterator is exhausted */
|
||||
PyObject *it_sentinel; /* Set to NULL when iterator is exhausted */
|
||||
} calliterobject;
|
||||
|
||||
PyObject *
|
||||
PyCallIter_New(PyObject *callable, PyObject *sentinel)
|
||||
{
|
||||
calliterobject *it;
|
||||
it = PyObject_GC_New(calliterobject, &PyCallIter_Type);
|
||||
if (it == NULL)
|
||||
return NULL;
|
||||
Py_INCREF(callable);
|
||||
it->it_callable = callable;
|
||||
Py_INCREF(sentinel);
|
||||
it->it_sentinel = sentinel;
|
||||
_PyObject_GC_TRACK(it);
|
||||
return (PyObject *)it;
|
||||
}
|
||||
static void
|
||||
calliter_dealloc(calliterobject *it)
|
||||
{
|
||||
_PyObject_GC_UNTRACK(it);
|
||||
Py_XDECREF(it->it_callable);
|
||||
Py_XDECREF(it->it_sentinel);
|
||||
PyObject_GC_Del(it);
|
||||
}
|
||||
|
||||
static int
|
||||
calliter_traverse(calliterobject *it, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(it->it_callable);
|
||||
Py_VISIT(it->it_sentinel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
calliter_iternext(calliterobject *it)
|
||||
{
|
||||
PyObject *result;
|
||||
|
||||
if (it->it_callable == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = _PyObject_CallNoArg(it->it_callable);
|
||||
if (result != NULL) {
|
||||
int ok;
|
||||
|
||||
ok = PyObject_RichCompareBool(it->it_sentinel, result, Py_EQ);
|
||||
if (ok == 0) {
|
||||
return result; /* Common case, fast path */
|
||||
}
|
||||
|
||||
Py_DECREF(result);
|
||||
if (ok > 0) {
|
||||
Py_CLEAR(it->it_callable);
|
||||
Py_CLEAR(it->it_sentinel);
|
||||
}
|
||||
}
|
||||
else if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
|
||||
PyErr_Clear();
|
||||
Py_CLEAR(it->it_callable);
|
||||
Py_CLEAR(it->it_sentinel);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
calliter_reduce(calliterobject *it)
|
||||
{
|
||||
if (it->it_callable != NULL && it->it_sentinel != NULL)
|
||||
return Py_BuildValue("N(OO)", _PyObject_GetBuiltin("iter"),
|
||||
it->it_callable, it->it_sentinel);
|
||||
else
|
||||
return Py_BuildValue("N(())", _PyObject_GetBuiltin("iter"));
|
||||
}
|
||||
|
||||
static PyMethodDef calliter_methods[] = {
|
||||
{"__reduce__", (PyCFunction)calliter_reduce, METH_NOARGS, reduce_doc},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
PyTypeObject PyCallIter_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"callable_iterator", /* tp_name */
|
||||
sizeof(calliterobject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
/* methods */
|
||||
(destructor)calliter_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 | Py_TPFLAGS_HAVE_GC,/* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc)calliter_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
PyObject_SelfIter, /* tp_iter */
|
||||
(iternextfunc)calliter_iternext, /* tp_iternext */
|
||||
calliter_methods, /* tp_methods */
|
||||
};
|
||||
|
||||
|
2991
third_party/python/Objects/listobject.c
vendored
Normal file
2991
third_party/python/Objects/listobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
755
third_party/python/Objects/listsort.txt
vendored
Normal file
755
third_party/python/Objects/listsort.txt
vendored
Normal file
|
@ -0,0 +1,755 @@
|
|||
Intro
|
||||
-----
|
||||
This describes an adaptive, stable, natural mergesort, modestly called
|
||||
timsort (hey, I earned it <wink>). It has supernatural performance on many
|
||||
kinds of partially ordered arrays (less than lg(N!) comparisons needed, and
|
||||
as few as N-1), yet as fast as Python's previous highly tuned samplesort
|
||||
hybrid on random arrays.
|
||||
|
||||
In a nutshell, the main routine marches over the array once, left to right,
|
||||
alternately identifying the next run, then merging it into the previous
|
||||
runs "intelligently". Everything else is complication for speed, and some
|
||||
hard-won measure of memory efficiency.
|
||||
|
||||
|
||||
Comparison with Python's Samplesort Hybrid
|
||||
------------------------------------------
|
||||
+ timsort can require a temp array containing as many as N//2 pointers,
|
||||
which means as many as 2*N extra bytes on 32-bit boxes. It can be
|
||||
expected to require a temp array this large when sorting random data; on
|
||||
data with significant structure, it may get away without using any extra
|
||||
heap memory. This appears to be the strongest argument against it, but
|
||||
compared to the size of an object, 2 temp bytes worst-case (also expected-
|
||||
case for random data) doesn't scare me much.
|
||||
|
||||
It turns out that Perl is moving to a stable mergesort, and the code for
|
||||
that appears always to require a temp array with room for at least N
|
||||
pointers. (Note that I wouldn't want to do that even if space weren't an
|
||||
issue; I believe its efforts at memory frugality also save timsort
|
||||
significant pointer-copying costs, and allow it to have a smaller working
|
||||
set.)
|
||||
|
||||
+ Across about four hours of generating random arrays, and sorting them
|
||||
under both methods, samplesort required about 1.5% more comparisons
|
||||
(the program is at the end of this file).
|
||||
|
||||
+ In real life, this may be faster or slower on random arrays than
|
||||
samplesort was, depending on platform quirks. Since it does fewer
|
||||
comparisons on average, it can be expected to do better the more
|
||||
expensive a comparison function is. OTOH, it does more data movement
|
||||
(pointer copying) than samplesort, and that may negate its small
|
||||
comparison advantage (depending on platform quirks) unless comparison
|
||||
is very expensive.
|
||||
|
||||
+ On arrays with many kinds of pre-existing order, this blows samplesort out
|
||||
of the water. It's significantly faster than samplesort even on some
|
||||
cases samplesort was special-casing the snot out of. I believe that lists
|
||||
very often do have exploitable partial order in real life, and this is the
|
||||
strongest argument in favor of timsort (indeed, samplesort's special cases
|
||||
for extreme partial order are appreciated by real users, and timsort goes
|
||||
much deeper than those, in particular naturally covering every case where
|
||||
someone has suggested "and it would be cool if list.sort() had a special
|
||||
case for this too ... and for that ...").
|
||||
|
||||
+ Here are exact comparison counts across all the tests in sortperf.py,
|
||||
when run with arguments "15 20 1".
|
||||
|
||||
Column Key:
|
||||
*sort: random data
|
||||
\sort: descending data
|
||||
/sort: ascending data
|
||||
3sort: ascending, then 3 random exchanges
|
||||
+sort: ascending, then 10 random at the end
|
||||
%sort: ascending, then randomly replace 1% of elements w/ random values
|
||||
~sort: many duplicates
|
||||
=sort: all equal
|
||||
!sort: worst case scenario
|
||||
|
||||
First the trivial cases, trivial for samplesort because it special-cased
|
||||
them, and trivial for timsort because it naturally works on runs. Within
|
||||
an "n" block, the first line gives the # of compares done by samplesort,
|
||||
the second line by timsort, and the third line is the percentage by
|
||||
which the samplesort count exceeds the timsort count:
|
||||
|
||||
n \sort /sort =sort
|
||||
------- ------ ------ ------
|
||||
32768 32768 32767 32767 samplesort
|
||||
32767 32767 32767 timsort
|
||||
0.00% 0.00% 0.00% (samplesort - timsort) / timsort
|
||||
|
||||
65536 65536 65535 65535
|
||||
65535 65535 65535
|
||||
0.00% 0.00% 0.00%
|
||||
|
||||
131072 131072 131071 131071
|
||||
131071 131071 131071
|
||||
0.00% 0.00% 0.00%
|
||||
|
||||
262144 262144 262143 262143
|
||||
262143 262143 262143
|
||||
0.00% 0.00% 0.00%
|
||||
|
||||
524288 524288 524287 524287
|
||||
524287 524287 524287
|
||||
0.00% 0.00% 0.00%
|
||||
|
||||
1048576 1048576 1048575 1048575
|
||||
1048575 1048575 1048575
|
||||
0.00% 0.00% 0.00%
|
||||
|
||||
The algorithms are effectively identical in these cases, except that
|
||||
timsort does one less compare in \sort.
|
||||
|
||||
Now for the more interesting cases. Where lg(x) is the logarithm of x to
|
||||
the base 2 (e.g., lg(8)=3), lg(n!) is the information-theoretic limit for
|
||||
the best any comparison-based sorting algorithm can do on average (across
|
||||
all permutations). When a method gets significantly below that, it's
|
||||
either astronomically lucky, or is finding exploitable structure in the
|
||||
data.
|
||||
|
||||
|
||||
n lg(n!) *sort 3sort +sort %sort ~sort !sort
|
||||
------- ------- ------ ------- ------- ------ ------- --------
|
||||
32768 444255 453096 453614 32908 452871 130491 469141 old
|
||||
448885 33016 33007 50426 182083 65534 new
|
||||
0.94% 1273.92% -0.30% 798.09% -28.33% 615.87% %ch from new
|
||||
|
||||
65536 954037 972699 981940 65686 973104 260029 1004607
|
||||
962991 65821 65808 101667 364341 131070
|
||||
1.01% 1391.83% -0.19% 857.15% -28.63% 666.47%
|
||||
|
||||
131072 2039137 2101881 2091491 131232 2092894 554790 2161379
|
||||
2057533 131410 131361 206193 728871 262142
|
||||
2.16% 1491.58% -0.10% 915.02% -23.88% 724.51%
|
||||
|
||||
262144 4340409 4464460 4403233 262314 4445884 1107842 4584560
|
||||
4377402 262437 262459 416347 1457945 524286
|
||||
1.99% 1577.82% -0.06% 967.83% -24.01% 774.44%
|
||||
|
||||
524288 9205096 9453356 9408463 524468 9441930 2218577 9692015
|
||||
9278734 524580 524633 837947 2916107 1048574
|
||||
1.88% 1693.52% -0.03% 1026.79% -23.92% 824.30%
|
||||
|
||||
1048576 19458756 19950272 19838588 1048766 19912134 4430649 20434212
|
||||
19606028 1048958 1048941 1694896 5832445 2097150
|
||||
1.76% 1791.27% -0.02% 1074.83% -24.03% 874.38%
|
||||
|
||||
Discussion of cases:
|
||||
|
||||
*sort: There's no structure in random data to exploit, so the theoretical
|
||||
limit is lg(n!). Both methods get close to that, and timsort is hugging
|
||||
it (indeed, in a *marginal* sense, it's a spectacular improvement --
|
||||
there's only about 1% left before hitting the wall, and timsort knows
|
||||
darned well it's doing compares that won't pay on random data -- but so
|
||||
does the samplesort hybrid). For contrast, Hoare's original random-pivot
|
||||
quicksort does about 39% more compares than the limit, and the median-of-3
|
||||
variant about 19% more.
|
||||
|
||||
3sort, %sort, and !sort: No contest; there's structure in this data, but
|
||||
not of the specific kinds samplesort special-cases. Note that structure
|
||||
in !sort wasn't put there on purpose -- it was crafted as a worst case for
|
||||
a previous quicksort implementation. That timsort nails it came as a
|
||||
surprise to me (although it's obvious in retrospect).
|
||||
|
||||
+sort: samplesort special-cases this data, and does a few less compares
|
||||
than timsort. However, timsort runs this case significantly faster on all
|
||||
boxes we have timings for, because timsort is in the business of merging
|
||||
runs efficiently, while samplesort does much more data movement in this
|
||||
(for it) special case.
|
||||
|
||||
~sort: samplesort's special cases for large masses of equal elements are
|
||||
extremely effective on ~sort's specific data pattern, and timsort just
|
||||
isn't going to get close to that, despite that it's clearly getting a
|
||||
great deal of benefit out of the duplicates (the # of compares is much less
|
||||
than lg(n!)). ~sort has a perfectly uniform distribution of just 4
|
||||
distinct values, and as the distribution gets more skewed, samplesort's
|
||||
equal-element gimmicks become less effective, while timsort's adaptive
|
||||
strategies find more to exploit; in a database supplied by Kevin Altis, a
|
||||
sort on its highly skewed "on which stock exchange does this company's
|
||||
stock trade?" field ran over twice as fast under timsort.
|
||||
|
||||
However, despite that timsort does many more comparisons on ~sort, and
|
||||
that on several platforms ~sort runs highly significantly slower under
|
||||
timsort, on other platforms ~sort runs highly significantly faster under
|
||||
timsort. No other kind of data has shown this wild x-platform behavior,
|
||||
and we don't have an explanation for it. The only thing I can think of
|
||||
that could transform what "should be" highly significant slowdowns into
|
||||
highly significant speedups on some boxes are catastrophic cache effects
|
||||
in samplesort.
|
||||
|
||||
But timsort "should be" slower than samplesort on ~sort, so it's hard
|
||||
to count that it isn't on some boxes as a strike against it <wink>.
|
||||
|
||||
+ Here's the highwater mark for the number of heap-based temp slots (4
|
||||
bytes each on this box) needed by each test, again with arguments
|
||||
"15 20 1":
|
||||
|
||||
2**i *sort \sort /sort 3sort +sort %sort ~sort =sort !sort
|
||||
32768 16384 0 0 6256 0 10821 12288 0 16383
|
||||
65536 32766 0 0 21652 0 31276 24576 0 32767
|
||||
131072 65534 0 0 17258 0 58112 49152 0 65535
|
||||
262144 131072 0 0 35660 0 123561 98304 0 131071
|
||||
524288 262142 0 0 31302 0 212057 196608 0 262143
|
||||
1048576 524286 0 0 312438 0 484942 393216 0 524287
|
||||
|
||||
Discussion: The tests that end up doing (close to) perfectly balanced
|
||||
merges (*sort, !sort) need all N//2 temp slots (or almost all). ~sort
|
||||
also ends up doing balanced merges, but systematically benefits a lot from
|
||||
the preliminary pre-merge searches described under "Merge Memory" later.
|
||||
%sort approaches having a balanced merge at the end because the random
|
||||
selection of elements to replace is expected to produce an out-of-order
|
||||
element near the midpoint. \sort, /sort, =sort are the trivial one-run
|
||||
cases, needing no merging at all. +sort ends up having one very long run
|
||||
and one very short, and so gets all the temp space it needs from the small
|
||||
temparray member of the MergeState struct (note that the same would be
|
||||
true if the new random elements were prefixed to the sorted list instead,
|
||||
but not if they appeared "in the middle"). 3sort approaches N//3 temp
|
||||
slots twice, but the run lengths that remain after 3 random exchanges
|
||||
clearly has very high variance.
|
||||
|
||||
|
||||
A detailed description of timsort follows.
|
||||
|
||||
Runs
|
||||
----
|
||||
count_run() returns the # of elements in the next run. A run is either
|
||||
"ascending", which means non-decreasing:
|
||||
|
||||
a0 <= a1 <= a2 <= ...
|
||||
|
||||
or "descending", which means strictly decreasing:
|
||||
|
||||
a0 > a1 > a2 > ...
|
||||
|
||||
Note that a run is always at least 2 long, unless we start at the array's
|
||||
last element.
|
||||
|
||||
The definition of descending is strict, because the main routine reverses
|
||||
a descending run in-place, transforming a descending run into an ascending
|
||||
run. Reversal is done via the obvious fast "swap elements starting at each
|
||||
end, and converge at the middle" method, and that can violate stability if
|
||||
the slice contains any equal elements. Using a strict definition of
|
||||
descending ensures that a descending run contains distinct elements.
|
||||
|
||||
If an array is random, it's very unlikely we'll see long runs. If a natural
|
||||
run contains less than minrun elements (see next section), the main loop
|
||||
artificially boosts it to minrun elements, via a stable binary insertion sort
|
||||
applied to the right number of array elements following the short natural
|
||||
run. In a random array, *all* runs are likely to be minrun long as a
|
||||
result. This has two primary good effects:
|
||||
|
||||
1. Random data strongly tends then toward perfectly balanced (both runs have
|
||||
the same length) merges, which is the most efficient way to proceed when
|
||||
data is random.
|
||||
|
||||
2. Because runs are never very short, the rest of the code doesn't make
|
||||
heroic efforts to shave a few cycles off per-merge overheads. For
|
||||
example, reasonable use of function calls is made, rather than trying to
|
||||
inline everything. Since there are no more than N/minrun runs to begin
|
||||
with, a few "extra" function calls per merge is barely measurable.
|
||||
|
||||
|
||||
Computing minrun
|
||||
----------------
|
||||
If N < 64, minrun is N. IOW, binary insertion sort is used for the whole
|
||||
array then; it's hard to beat that given the overheads of trying something
|
||||
fancier (see note BINSORT).
|
||||
|
||||
When N is a power of 2, testing on random data showed that minrun values of
|
||||
16, 32, 64 and 128 worked about equally well. At 256 the data-movement cost
|
||||
in binary insertion sort clearly hurt, and at 8 the increase in the number
|
||||
of function calls clearly hurt. Picking *some* power of 2 is important
|
||||
here, so that the merges end up perfectly balanced (see next section). We
|
||||
pick 32 as a good value in the sweet range; picking a value at the low end
|
||||
allows the adaptive gimmicks more opportunity to exploit shorter natural
|
||||
runs.
|
||||
|
||||
Because sortperf.py only tries powers of 2, it took a long time to notice
|
||||
that 32 isn't a good choice for the general case! Consider N=2112:
|
||||
|
||||
>>> divmod(2112, 32)
|
||||
(66, 0)
|
||||
>>>
|
||||
|
||||
If the data is randomly ordered, we're very likely to end up with 66 runs
|
||||
each of length 32. The first 64 of these trigger a sequence of perfectly
|
||||
balanced merges (see next section), leaving runs of lengths 2048 and 64 to
|
||||
merge at the end. The adaptive gimmicks can do that with fewer than 2048+64
|
||||
compares, but it's still more compares than necessary, and-- mergesort's
|
||||
bugaboo relative to samplesort --a lot more data movement (O(N) copies just
|
||||
to get 64 elements into place).
|
||||
|
||||
If we take minrun=33 in this case, then we're very likely to end up with 64
|
||||
runs each of length 33, and then all merges are perfectly balanced. Better!
|
||||
|
||||
What we want to avoid is picking minrun such that in
|
||||
|
||||
q, r = divmod(N, minrun)
|
||||
|
||||
q is a power of 2 and r>0 (then the last merge only gets r elements into
|
||||
place, and r < minrun is small compared to N), or q a little larger than a
|
||||
power of 2 regardless of r (then we've got a case similar to "2112", again
|
||||
leaving too little work for the last merge to do).
|
||||
|
||||
Instead we pick a minrun in range(32, 65) such that N/minrun is exactly a
|
||||
power of 2, or if that isn't possible, is close to, but strictly less than,
|
||||
a power of 2. This is easier to do than it may sound: take the first 6
|
||||
bits of N, and add 1 if any of the remaining bits are set. In fact, that
|
||||
rule covers every case in this section, including small N and exact powers
|
||||
of 2; merge_compute_minrun() is a deceptively simple function.
|
||||
|
||||
|
||||
The Merge Pattern
|
||||
-----------------
|
||||
In order to exploit regularities in the data, we're merging on natural
|
||||
run lengths, and they can become wildly unbalanced. That's a Good Thing
|
||||
for this sort! It means we have to find a way to manage an assortment of
|
||||
potentially very different run lengths, though.
|
||||
|
||||
Stability constrains permissible merging patterns. For example, if we have
|
||||
3 consecutive runs of lengths
|
||||
|
||||
A:10000 B:20000 C:10000
|
||||
|
||||
we dare not merge A with C first, because if A, B and C happen to contain
|
||||
a common element, it would get out of order wrt its occurrence(s) in B. The
|
||||
merging must be done as (A+B)+C or A+(B+C) instead.
|
||||
|
||||
So merging is always done on two consecutive runs at a time, and in-place,
|
||||
although this may require some temp memory (more on that later).
|
||||
|
||||
When a run is identified, its base address and length are pushed on a stack
|
||||
in the MergeState struct. merge_collapse() is then called to see whether it
|
||||
should merge it with preceding run(s). We would like to delay merging as
|
||||
long as possible in order to exploit patterns that may come up later, but we
|
||||
like even more to do merging as soon as possible to exploit that the run just
|
||||
found is still high in the memory hierarchy. We also can't delay merging
|
||||
"too long" because it consumes memory to remember the runs that are still
|
||||
unmerged, and the stack has a fixed size.
|
||||
|
||||
What turned out to be a good compromise maintains two invariants on the
|
||||
stack entries, where A, B and C are the lengths of the three righmost not-yet
|
||||
merged slices:
|
||||
|
||||
1. A > B+C
|
||||
2. B > C
|
||||
|
||||
Note that, by induction, #2 implies the lengths of pending runs form a
|
||||
decreasing sequence. #1 implies that, reading the lengths right to left,
|
||||
the pending-run lengths grow at least as fast as the Fibonacci numbers.
|
||||
Therefore the stack can never grow larger than about log_base_phi(N) entries,
|
||||
where phi = (1+sqrt(5))/2 ~= 1.618. Thus a small # of stack slots suffice
|
||||
for very large arrays.
|
||||
|
||||
If A <= B+C, the smaller of A and C is merged with B (ties favor C, for the
|
||||
freshness-in-cache reason), and the new run replaces the A,B or B,C entries;
|
||||
e.g., if the last 3 entries are
|
||||
|
||||
A:30 B:20 C:10
|
||||
|
||||
then B is merged with C, leaving
|
||||
|
||||
A:30 BC:30
|
||||
|
||||
on the stack. Or if they were
|
||||
|
||||
A:500 B:400: C:1000
|
||||
|
||||
then A is merged with B, leaving
|
||||
|
||||
AB:900 C:1000
|
||||
|
||||
on the stack.
|
||||
|
||||
In both examples, the stack configuration after the merge still violates
|
||||
invariant #2, and merge_collapse() goes on to continue merging runs until
|
||||
both invariants are satisfied. As an extreme case, suppose we didn't do the
|
||||
minrun gimmick, and natural runs were of lengths 128, 64, 32, 16, 8, 4, 2,
|
||||
and 2. Nothing would get merged until the final 2 was seen, and that would
|
||||
trigger 7 perfectly balanced merges.
|
||||
|
||||
The thrust of these rules when they trigger merging is to balance the run
|
||||
lengths as closely as possible, while keeping a low bound on the number of
|
||||
runs we have to remember. This is maximally effective for random data,
|
||||
where all runs are likely to be of (artificially forced) length minrun, and
|
||||
then we get a sequence of perfectly balanced merges (with, perhaps, some
|
||||
oddballs at the end).
|
||||
|
||||
OTOH, one reason this sort is so good for partly ordered data has to do
|
||||
with wildly unbalanced run lengths.
|
||||
|
||||
|
||||
Merge Memory
|
||||
------------
|
||||
Merging adjacent runs of lengths A and B in-place, and in linear time, is
|
||||
difficult. Theoretical constructions are known that can do it, but they're
|
||||
too difficult and slow for practical use. But if we have temp memory equal
|
||||
to min(A, B), it's easy.
|
||||
|
||||
If A is smaller (function merge_lo), copy A to a temp array, leave B alone,
|
||||
and then we can do the obvious merge algorithm left to right, from the temp
|
||||
area and B, starting the stores into where A used to live. There's always a
|
||||
free area in the original area comprising a number of elements equal to the
|
||||
number not yet merged from the temp array (trivially true at the start;
|
||||
proceed by induction). The only tricky bit is that if a comparison raises an
|
||||
exception, we have to remember to copy the remaining elements back in from
|
||||
the temp area, lest the array end up with duplicate entries from B. But
|
||||
that's exactly the same thing we need to do if we reach the end of B first,
|
||||
so the exit code is pleasantly common to both the normal and error cases.
|
||||
|
||||
If B is smaller (function merge_hi, which is merge_lo's "mirror image"),
|
||||
much the same, except that we need to merge right to left, copying B into a
|
||||
temp array and starting the stores at the right end of where B used to live.
|
||||
|
||||
A refinement: When we're about to merge adjacent runs A and B, we first do
|
||||
a form of binary search (more on that later) to see where B[0] should end up
|
||||
in A. Elements in A preceding that point are already in their final
|
||||
positions, effectively shrinking the size of A. Likewise we also search to
|
||||
see where A[-1] should end up in B, and elements of B after that point can
|
||||
also be ignored. This cuts the amount of temp memory needed by the same
|
||||
amount.
|
||||
|
||||
These preliminary searches may not pay off, and can be expected *not* to
|
||||
repay their cost if the data is random. But they can win huge in all of
|
||||
time, copying, and memory savings when they do pay, so this is one of the
|
||||
"per-merge overheads" mentioned above that we're happy to endure because
|
||||
there is at most one very short run. It's generally true in this algorithm
|
||||
that we're willing to gamble a little to win a lot, even though the net
|
||||
expectation is negative for random data.
|
||||
|
||||
|
||||
Merge Algorithms
|
||||
----------------
|
||||
merge_lo() and merge_hi() are where the bulk of the time is spent. merge_lo
|
||||
deals with runs where A <= B, and merge_hi where A > B. They don't know
|
||||
whether the data is clustered or uniform, but a lovely thing about merging
|
||||
is that many kinds of clustering "reveal themselves" by how many times in a
|
||||
row the winning merge element comes from the same run. We'll only discuss
|
||||
merge_lo here; merge_hi is exactly analogous.
|
||||
|
||||
Merging begins in the usual, obvious way, comparing the first element of A
|
||||
to the first of B, and moving B[0] to the merge area if it's less than A[0],
|
||||
else moving A[0] to the merge area. Call that the "one pair at a time"
|
||||
mode. The only twist here is keeping track of how many times in a row "the
|
||||
winner" comes from the same run.
|
||||
|
||||
If that count reaches MIN_GALLOP, we switch to "galloping mode". Here
|
||||
we *search* B for where A[0] belongs, and move over all the B's before
|
||||
that point in one chunk to the merge area, then move A[0] to the merge
|
||||
area. Then we search A for where B[0] belongs, and similarly move a
|
||||
slice of A in one chunk. Then back to searching B for where A[0] belongs,
|
||||
etc. We stay in galloping mode until both searches find slices to copy
|
||||
less than MIN_GALLOP elements long, at which point we go back to one-pair-
|
||||
at-a-time mode.
|
||||
|
||||
A refinement: The MergeState struct contains the value of min_gallop that
|
||||
controls when we enter galloping mode, initialized to MIN_GALLOP.
|
||||
merge_lo() and merge_hi() adjust this higher when galloping isn't paying
|
||||
off, and lower when it is.
|
||||
|
||||
|
||||
Galloping
|
||||
---------
|
||||
Still without loss of generality, assume A is the shorter run. In galloping
|
||||
mode, we first look for A[0] in B. We do this via "galloping", comparing
|
||||
A[0] in turn to B[0], B[1], B[3], B[7], ..., B[2**j - 1], ..., until finding
|
||||
the k such that B[2**(k-1) - 1] < A[0] <= B[2**k - 1]. This takes at most
|
||||
roughly lg(B) comparisons, and, unlike a straight binary search, favors
|
||||
finding the right spot early in B (more on that later).
|
||||
|
||||
After finding such a k, the region of uncertainty is reduced to 2**(k-1) - 1
|
||||
consecutive elements, and a straight binary search requires exactly k-1
|
||||
additional comparisons to nail it (see note REGION OF UNCERTAINTY). Then we
|
||||
copy all the B's up to that point in one chunk, and then copy A[0]. Note
|
||||
that no matter where A[0] belongs in B, the combination of galloping + binary
|
||||
search finds it in no more than about 2*lg(B) comparisons.
|
||||
|
||||
If we did a straight binary search, we could find it in no more than
|
||||
ceiling(lg(B+1)) comparisons -- but straight binary search takes that many
|
||||
comparisons no matter where A[0] belongs. Straight binary search thus loses
|
||||
to galloping unless the run is quite long, and we simply can't guess
|
||||
whether it is in advance.
|
||||
|
||||
If data is random and runs have the same length, A[0] belongs at B[0] half
|
||||
the time, at B[1] a quarter of the time, and so on: a consecutive winning
|
||||
sub-run in B of length k occurs with probability 1/2**(k+1). So long
|
||||
winning sub-runs are extremely unlikely in random data, and guessing that a
|
||||
winning sub-run is going to be long is a dangerous game.
|
||||
|
||||
OTOH, if data is lopsided or lumpy or contains many duplicates, long
|
||||
stretches of winning sub-runs are very likely, and cutting the number of
|
||||
comparisons needed to find one from O(B) to O(log B) is a huge win.
|
||||
|
||||
Galloping compromises by getting out fast if there isn't a long winning
|
||||
sub-run, yet finding such very efficiently when they exist.
|
||||
|
||||
I first learned about the galloping strategy in a related context; see:
|
||||
|
||||
"Adaptive Set Intersections, Unions, and Differences" (2000)
|
||||
Erik D. Demaine, Alejandro López-Ortiz, J. Ian Munro
|
||||
|
||||
and its followup(s). An earlier paper called the same strategy
|
||||
"exponential search":
|
||||
|
||||
"Optimistic Sorting and Information Theoretic Complexity"
|
||||
Peter McIlroy
|
||||
SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms), pp
|
||||
467-474, Austin, Texas, 25-27 January 1993.
|
||||
|
||||
and it probably dates back to an earlier paper by Bentley and Yao. The
|
||||
McIlroy paper in particular has good analysis of a mergesort that's
|
||||
probably strongly related to this one in its galloping strategy.
|
||||
|
||||
|
||||
Galloping with a Broken Leg
|
||||
---------------------------
|
||||
So why don't we always gallop? Because it can lose, on two counts:
|
||||
|
||||
1. While we're willing to endure small per-merge overheads, per-comparison
|
||||
overheads are a different story. Calling Yet Another Function per
|
||||
comparison is expensive, and gallop_left() and gallop_right() are
|
||||
too long-winded for sane inlining.
|
||||
|
||||
2. Galloping can-- alas --require more comparisons than linear one-at-time
|
||||
search, depending on the data.
|
||||
|
||||
#2 requires details. If A[0] belongs before B[0], galloping requires 1
|
||||
compare to determine that, same as linear search, except it costs more
|
||||
to call the gallop function. If A[0] belongs right before B[1], galloping
|
||||
requires 2 compares, again same as linear search. On the third compare,
|
||||
galloping checks A[0] against B[3], and if it's <=, requires one more
|
||||
compare to determine whether A[0] belongs at B[2] or B[3]. That's a total
|
||||
of 4 compares, but if A[0] does belong at B[2], linear search would have
|
||||
discovered that in only 3 compares, and that's a huge loss! Really. It's
|
||||
an increase of 33% in the number of compares needed, and comparisons are
|
||||
expensive in Python.
|
||||
|
||||
index in B where # compares linear # gallop # binary gallop
|
||||
A[0] belongs search needs compares compares total
|
||||
---------------- ----------------- -------- -------- ------
|
||||
0 1 1 0 1
|
||||
|
||||
1 2 2 0 2
|
||||
|
||||
2 3 3 1 4
|
||||
3 4 3 1 4
|
||||
|
||||
4 5 4 2 6
|
||||
5 6 4 2 6
|
||||
6 7 4 2 6
|
||||
7 8 4 2 6
|
||||
|
||||
8 9 5 3 8
|
||||
9 10 5 3 8
|
||||
10 11 5 3 8
|
||||
11 12 5 3 8
|
||||
...
|
||||
|
||||
In general, if A[0] belongs at B[i], linear search requires i+1 comparisons
|
||||
to determine that, and galloping a total of 2*floor(lg(i))+2 comparisons.
|
||||
The advantage of galloping is unbounded as i grows, but it doesn't win at
|
||||
all until i=6. Before then, it loses twice (at i=2 and i=4), and ties
|
||||
at the other values. At and after i=6, galloping always wins.
|
||||
|
||||
We can't guess in advance when it's going to win, though, so we do one pair
|
||||
at a time until the evidence seems strong that galloping may pay. MIN_GALLOP
|
||||
is 7, and that's pretty strong evidence. However, if the data is random, it
|
||||
simply will trigger galloping mode purely by luck every now and again, and
|
||||
it's quite likely to hit one of the losing cases next. On the other hand,
|
||||
in cases like ~sort, galloping always pays, and MIN_GALLOP is larger than it
|
||||
"should be" then. So the MergeState struct keeps a min_gallop variable
|
||||
that merge_lo and merge_hi adjust: the longer we stay in galloping mode,
|
||||
the smaller min_gallop gets, making it easier to transition back to
|
||||
galloping mode (if we ever leave it in the current merge, and at the
|
||||
start of the next merge). But whenever the gallop loop doesn't pay,
|
||||
min_gallop is increased by one, making it harder to transition back
|
||||
to galloping mode (and again both within a merge and across merges). For
|
||||
random data, this all but eliminates the gallop penalty: min_gallop grows
|
||||
large enough that we almost never get into galloping mode. And for cases
|
||||
like ~sort, min_gallop can fall to as low as 1. This seems to work well,
|
||||
but in all it's a minor improvement over using a fixed MIN_GALLOP value.
|
||||
|
||||
|
||||
Galloping Complication
|
||||
----------------------
|
||||
The description above was for merge_lo. merge_hi has to merge "from the
|
||||
other end", and really needs to gallop starting at the last element in a run
|
||||
instead of the first. Galloping from the first still works, but does more
|
||||
comparisons than it should (this is significant -- I timed it both ways). For
|
||||
this reason, the gallop_left() and gallop_right() (see note LEFT OR RIGHT)
|
||||
functions have a "hint" argument, which is the index at which galloping
|
||||
should begin. So galloping can actually start at any index, and proceed at
|
||||
offsets of 1, 3, 7, 15, ... or -1, -3, -7, -15, ... from the starting index.
|
||||
|
||||
In the code as I type it's always called with either 0 or n-1 (where n is
|
||||
the # of elements in a run). It's tempting to try to do something fancier,
|
||||
melding galloping with some form of interpolation search; for example, if
|
||||
we're merging a run of length 1 with a run of length 10000, index 5000 is
|
||||
probably a better guess at the final result than either 0 or 9999. But
|
||||
it's unclear how to generalize that intuition usefully, and merging of
|
||||
wildly unbalanced runs already enjoys excellent performance.
|
||||
|
||||
~sort is a good example of when balanced runs could benefit from a better
|
||||
hint value: to the extent possible, this would like to use a starting
|
||||
offset equal to the previous value of acount/bcount. Doing so saves about
|
||||
10% of the compares in ~sort. However, doing so is also a mixed bag,
|
||||
hurting other cases.
|
||||
|
||||
|
||||
Comparing Average # of Compares on Random Arrays
|
||||
------------------------------------------------
|
||||
[NOTE: This was done when the new algorithm used about 0.1% more compares
|
||||
on random data than does its current incarnation.]
|
||||
|
||||
Here list.sort() is samplesort, and list.msort() this sort:
|
||||
|
||||
"""
|
||||
import random
|
||||
from time import clock as now
|
||||
|
||||
def fill(n):
|
||||
from random import random
|
||||
return [random() for i in range(n)]
|
||||
|
||||
def mycmp(x, y):
|
||||
global ncmp
|
||||
ncmp += 1
|
||||
return cmp(x, y)
|
||||
|
||||
def timeit(values, method):
|
||||
global ncmp
|
||||
X = values[:]
|
||||
bound = getattr(X, method)
|
||||
ncmp = 0
|
||||
t1 = now()
|
||||
bound(mycmp)
|
||||
t2 = now()
|
||||
return t2-t1, ncmp
|
||||
|
||||
format = "%5s %9.2f %11d"
|
||||
f2 = "%5s %9.2f %11.2f"
|
||||
|
||||
def drive():
|
||||
count = sst = sscmp = mst = mscmp = nelts = 0
|
||||
while True:
|
||||
n = random.randrange(100000)
|
||||
nelts += n
|
||||
x = fill(n)
|
||||
|
||||
t, c = timeit(x, 'sort')
|
||||
sst += t
|
||||
sscmp += c
|
||||
|
||||
t, c = timeit(x, 'msort')
|
||||
mst += t
|
||||
mscmp += c
|
||||
|
||||
count += 1
|
||||
if count % 10:
|
||||
continue
|
||||
|
||||
print "count", count, "nelts", nelts
|
||||
print format % ("sort", sst, sscmp)
|
||||
print format % ("msort", mst, mscmp)
|
||||
print f2 % ("", (sst-mst)*1e2/mst, (sscmp-mscmp)*1e2/mscmp)
|
||||
|
||||
drive()
|
||||
"""
|
||||
|
||||
I ran this on Windows and kept using the computer lightly while it was
|
||||
running. time.clock() is wall-clock time on Windows, with better than
|
||||
microsecond resolution. samplesort started with a 1.52% #-of-comparisons
|
||||
disadvantage, fell quickly to 1.48%, and then fluctuated within that small
|
||||
range. Here's the last chunk of output before I killed the job:
|
||||
|
||||
count 2630 nelts 130906543
|
||||
sort 6110.80 1937887573
|
||||
msort 6002.78 1909389381
|
||||
1.80 1.49
|
||||
|
||||
We've done nearly 2 billion comparisons apiece at Python speed there, and
|
||||
that's enough <wink>.
|
||||
|
||||
For random arrays of size 2 (yes, there are only 2 interesting ones),
|
||||
samplesort has a 50%(!) comparison disadvantage. This is a consequence of
|
||||
samplesort special-casing at most one ascending run at the start, then
|
||||
falling back to the general case if it doesn't find an ascending run
|
||||
immediately. The consequence is that it ends up using two compares to sort
|
||||
[2, 1]. Gratifyingly, timsort doesn't do any special-casing, so had to be
|
||||
taught how to deal with mixtures of ascending and descending runs
|
||||
efficiently in all cases.
|
||||
|
||||
|
||||
NOTES
|
||||
-----
|
||||
|
||||
BINSORT
|
||||
A "binary insertion sort" is just like a textbook insertion sort, but instead
|
||||
of locating the correct position of the next item via linear (one at a time)
|
||||
search, an equivalent to Python's bisect.bisect_right is used to find the
|
||||
correct position in logarithmic time. Most texts don't mention this
|
||||
variation, and those that do usually say it's not worth the bother: insertion
|
||||
sort remains quadratic (expected and worst cases) either way. Speeding the
|
||||
search doesn't reduce the quadratic data movement costs.
|
||||
|
||||
But in CPython's case, comparisons are extraordinarily expensive compared to
|
||||
moving data, and the details matter. Moving objects is just copying
|
||||
pointers. Comparisons can be arbitrarily expensive (can invoke arbitrary
|
||||
user-supplied Python code), but even in simple cases (like 3 < 4) _all_
|
||||
decisions are made at runtime: what's the type of the left comparand? the
|
||||
type of the right? do they need to be coerced to a common type? where's the
|
||||
code to compare these types? And so on. Even the simplest Python comparison
|
||||
triggers a large pile of C-level pointer dereferences, conditionals, and
|
||||
function calls.
|
||||
|
||||
So cutting the number of compares is almost always measurably helpful in
|
||||
CPython, and the savings swamp the quadratic-time data movement costs for
|
||||
reasonable minrun values.
|
||||
|
||||
|
||||
LEFT OR RIGHT
|
||||
gallop_left() and gallop_right() are akin to the Python bisect module's
|
||||
bisect_left() and bisect_right(): they're the same unless the slice they're
|
||||
searching contains a (at least one) value equal to the value being searched
|
||||
for. In that case, gallop_left() returns the position immediately before the
|
||||
leftmost equal value, and gallop_right() the position immediately after the
|
||||
rightmost equal value. The distinction is needed to preserve stability. In
|
||||
general, when merging adjacent runs A and B, gallop_left is used to search
|
||||
thru B for where an element from A belongs, and gallop_right to search thru A
|
||||
for where an element from B belongs.
|
||||
|
||||
|
||||
REGION OF UNCERTAINTY
|
||||
Two kinds of confusion seem to be common about the claim that after finding
|
||||
a k such that
|
||||
|
||||
B[2**(k-1) - 1] < A[0] <= B[2**k - 1]
|
||||
|
||||
then a binary search requires exactly k-1 tries to find A[0]'s proper
|
||||
location. For concreteness, say k=3, so B[3] < A[0] <= B[7].
|
||||
|
||||
The first confusion takes the form "OK, then the region of uncertainty is at
|
||||
indices 3, 4, 5, 6 and 7: that's 5 elements, not the claimed 2**(k-1) - 1 =
|
||||
3"; or the region is viewed as a Python slice and the objection is "but that's
|
||||
the slice B[3:7], so has 7-3 = 4 elements". Resolution: we've already
|
||||
compared A[0] against B[3] and against B[7], so A[0]'s correct location is
|
||||
already known wrt _both_ endpoints. What remains is to find A[0]'s correct
|
||||
location wrt B[4], B[5] and B[6], which spans 3 elements. Or in general, the
|
||||
slice (leaving off both endpoints) (2**(k-1)-1)+1 through (2**k-1)-1
|
||||
inclusive = 2**(k-1) through (2**k-1)-1 inclusive, which has
|
||||
(2**k-1)-1 - 2**(k-1) + 1 =
|
||||
2**k-1 - 2**(k-1) =
|
||||
2*2**k-1 - 2**(k-1) =
|
||||
(2-1)*2**(k-1) - 1 =
|
||||
2**(k-1) - 1
|
||||
elements.
|
||||
|
||||
The second confusion: "k-1 = 2 binary searches can find the correct location
|
||||
among 2**(k-1) = 4 elements, but you're only applying it to 3 elements: we
|
||||
could make this more efficient by arranging for the region of uncertainty to
|
||||
span 2**(k-1) elements." Resolution: that confuses "elements" with
|
||||
"locations". In a slice with N elements, there are N+1 _locations_. In the
|
||||
example, with the region of uncertainty B[4], B[5], B[6], there are 4
|
||||
locations: before B[4], between B[4] and B[5], between B[5] and B[6], and
|
||||
after B[6]. In general, across 2**(k-1)-1 elements, there are 2**(k-1)
|
||||
locations. That's why k-1 binary searches are necessary and sufficient.
|
135
third_party/python/Objects/lnotab_notes.txt
vendored
Normal file
135
third_party/python/Objects/lnotab_notes.txt
vendored
Normal file
|
@ -0,0 +1,135 @@
|
|||
All about co_lnotab, the line number table.
|
||||
|
||||
Code objects store a field named co_lnotab. This is an array of unsigned bytes
|
||||
disguised as a Python bytes object. It is used to map bytecode offsets to
|
||||
source code line #s for tracebacks and to identify line number boundaries for
|
||||
line tracing.
|
||||
|
||||
The array is conceptually a compressed list of
|
||||
(bytecode offset increment, line number increment)
|
||||
pairs. The details are important and delicate, best illustrated by example:
|
||||
|
||||
byte code offset source code line number
|
||||
0 1
|
||||
6 2
|
||||
50 7
|
||||
350 207
|
||||
361 208
|
||||
|
||||
Instead of storing these numbers literally, we compress the list by storing only
|
||||
the difference from one row to the next. Conceptually, the stored list might
|
||||
look like:
|
||||
|
||||
0, 1, 6, 1, 44, 5, 300, 200, 11, 1
|
||||
|
||||
The above doesn't really work, but it's a start. An unsigned byte (byte code
|
||||
offset) can't hold negative values, or values larger than 255, a signed byte
|
||||
(line number) can't hold values larger than 127 or less than -128, and the
|
||||
above example contains two such values. (Note that before 3.6, line number
|
||||
was also encoded by an unsigned byte.) So we make two tweaks:
|
||||
|
||||
(a) there's a deep assumption that byte code offsets increase monotonically,
|
||||
and
|
||||
(b) if byte code offset jumps by more than 255 from one row to the next, or if
|
||||
source code line number jumps by more than 127 or less than -128 from one row
|
||||
to the next, more than one pair is written to the table. In case #b,
|
||||
there's no way to know from looking at the table later how many were written.
|
||||
That's the delicate part. A user of co_lnotab desiring to find the source
|
||||
line number corresponding to a bytecode address A should do something like
|
||||
this:
|
||||
|
||||
lineno = addr = 0
|
||||
for addr_incr, line_incr in co_lnotab:
|
||||
addr += addr_incr
|
||||
if addr > A:
|
||||
return lineno
|
||||
if line_incr >= 0x80:
|
||||
line_incr -= 0x100
|
||||
lineno += line_incr
|
||||
|
||||
(In C, this is implemented by PyCode_Addr2Line().) In order for this to work,
|
||||
when the addr field increments by more than 255, the line # increment in each
|
||||
pair generated must be 0 until the remaining addr increment is < 256. So, in
|
||||
the example above, assemble_lnotab in compile.c should not (as was actually done
|
||||
until 2.2) expand 300, 200 to
|
||||
255, 255, 45, 45,
|
||||
but to
|
||||
255, 0, 45, 127, 0, 73.
|
||||
|
||||
The above is sufficient to reconstruct line numbers for tracebacks, but not for
|
||||
line tracing. Tracing is handled by PyCode_CheckLineNumber() in codeobject.c
|
||||
and maybe_call_line_trace() in ceval.c.
|
||||
|
||||
*** Tracing ***
|
||||
|
||||
To a first approximation, we want to call the tracing function when the line
|
||||
number of the current instruction changes. Re-computing the current line for
|
||||
every instruction is a little slow, though, so each time we compute the line
|
||||
number we save the bytecode indices where it's valid:
|
||||
|
||||
*instr_lb <= frame->f_lasti < *instr_ub
|
||||
|
||||
is true so long as execution does not change lines. That is, *instr_lb holds
|
||||
the first bytecode index of the current line, and *instr_ub holds the first
|
||||
bytecode index of the next line. As long as the above expression is true,
|
||||
maybe_call_line_trace() does not need to call PyCode_CheckLineNumber(). Note
|
||||
that the same line may appear multiple times in the lnotab, either because the
|
||||
bytecode jumped more than 255 indices between line number changes or because
|
||||
the compiler inserted the same line twice. Even in that case, *instr_ub holds
|
||||
the first index of the next line.
|
||||
|
||||
However, we don't *always* want to call the line trace function when the above
|
||||
test fails.
|
||||
|
||||
Consider this code:
|
||||
|
||||
1: def f(a):
|
||||
2: while a:
|
||||
3: print(1)
|
||||
4: break
|
||||
5: else:
|
||||
6: print(2)
|
||||
|
||||
which compiles to this:
|
||||
|
||||
2 0 SETUP_LOOP 26 (to 28)
|
||||
>> 2 LOAD_FAST 0 (a)
|
||||
4 POP_JUMP_IF_FALSE 18
|
||||
|
||||
3 6 LOAD_GLOBAL 0 (print)
|
||||
8 LOAD_CONST 1 (1)
|
||||
10 CALL_FUNCTION 1
|
||||
12 POP_TOP
|
||||
|
||||
4 14 BREAK_LOOP
|
||||
16 JUMP_ABSOLUTE 2
|
||||
>> 18 POP_BLOCK
|
||||
|
||||
6 20 LOAD_GLOBAL 0 (print)
|
||||
22 LOAD_CONST 2 (2)
|
||||
24 CALL_FUNCTION 1
|
||||
26 POP_TOP
|
||||
>> 28 LOAD_CONST 0 (None)
|
||||
30 RETURN_VALUE
|
||||
|
||||
If 'a' is false, execution will jump to the POP_BLOCK instruction at offset 18
|
||||
and the co_lnotab will claim that execution has moved to line 4, which is wrong.
|
||||
In this case, we could instead associate the POP_BLOCK with line 5, but that
|
||||
would break jumps around loops without else clauses.
|
||||
|
||||
We fix this by only calling the line trace function for a forward jump if the
|
||||
co_lnotab indicates we have jumped to the *start* of a line, i.e. if the current
|
||||
instruction offset matches the offset given for the start of a line by the
|
||||
co_lnotab. For backward jumps, however, we always call the line trace function,
|
||||
which lets a debugger stop on every evaluation of a loop guard (which usually
|
||||
won't be the first opcode in a line).
|
||||
|
||||
Why do we set f_lineno when tracing, and only just before calling the trace
|
||||
function? Well, consider the code above when 'a' is true. If stepping through
|
||||
this with 'n' in pdb, you would stop at line 1 with a "call" type event, then
|
||||
line events on lines 2, 3, and 4, then a "return" type event -- but because the
|
||||
code for the return actually falls in the range of the "line 6" opcodes, you
|
||||
would be shown line 6 during this event. This is a change from the behaviour in
|
||||
2.2 and before, and I've found it confusing in practice. By setting and using
|
||||
f_lineno when tracing, one can report a line number different from that
|
||||
suggested by f_lasti on this one occasion where it's desirable.
|
5569
third_party/python/Objects/longobject.c
vendored
Normal file
5569
third_party/python/Objects/longobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
3114
third_party/python/Objects/memoryobject.c
vendored
Normal file
3114
third_party/python/Objects/memoryobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
550
third_party/python/Objects/methodobject.c
vendored
Normal file
550
third_party/python/Objects/methodobject.c
vendored
Normal file
|
@ -0,0 +1,550 @@
|
|||
|
||||
/* Method object implementation */
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
|
||||
/* Free list for method objects to safe malloc/free overhead
|
||||
* The m_self element is used to chain the objects.
|
||||
*/
|
||||
static PyCFunctionObject *free_list = NULL;
|
||||
static int numfree = 0;
|
||||
#ifndef PyCFunction_MAXFREELIST
|
||||
#define PyCFunction_MAXFREELIST 256
|
||||
#endif
|
||||
|
||||
/* undefine macro trampoline to PyCFunction_NewEx */
|
||||
#undef PyCFunction_New
|
||||
|
||||
PyAPI_FUNC(PyObject *)
|
||||
PyCFunction_New(PyMethodDef *ml, PyObject *self)
|
||||
{
|
||||
return PyCFunction_NewEx(ml, self, NULL);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
|
||||
{
|
||||
PyCFunctionObject *op;
|
||||
op = free_list;
|
||||
if (op != NULL) {
|
||||
free_list = (PyCFunctionObject *)(op->m_self);
|
||||
(void)PyObject_INIT(op, &PyCFunction_Type);
|
||||
numfree--;
|
||||
}
|
||||
else {
|
||||
op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type);
|
||||
if (op == NULL)
|
||||
return NULL;
|
||||
}
|
||||
op->m_weakreflist = NULL;
|
||||
op->m_ml = ml;
|
||||
Py_XINCREF(self);
|
||||
op->m_self = self;
|
||||
Py_XINCREF(module);
|
||||
op->m_module = module;
|
||||
_PyObject_GC_TRACK(op);
|
||||
return (PyObject *)op;
|
||||
}
|
||||
|
||||
PyCFunction
|
||||
PyCFunction_GetFunction(PyObject *op)
|
||||
{
|
||||
if (!PyCFunction_Check(op)) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
return PyCFunction_GET_FUNCTION(op);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyCFunction_GetSelf(PyObject *op)
|
||||
{
|
||||
if (!PyCFunction_Check(op)) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
return PyCFunction_GET_SELF(op);
|
||||
}
|
||||
|
||||
int
|
||||
PyCFunction_GetFlags(PyObject *op)
|
||||
{
|
||||
if (!PyCFunction_Check(op)) {
|
||||
PyErr_BadInternalCall();
|
||||
return -1;
|
||||
}
|
||||
return PyCFunction_GET_FLAGS(op);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyCFunctionObject* f = (PyCFunctionObject*)func;
|
||||
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
|
||||
PyObject *self = PyCFunction_GET_SELF(func);
|
||||
PyObject *arg, *res;
|
||||
Py_ssize_t size;
|
||||
int flags;
|
||||
|
||||
/* PyCFunction_Call() must not be called with an exception set,
|
||||
because it may clear it (directly or indirectly) and so the
|
||||
caller loses its exception */
|
||||
assert(!PyErr_Occurred());
|
||||
|
||||
flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
|
||||
|
||||
if (flags == (METH_VARARGS | METH_KEYWORDS)) {
|
||||
res = (*(PyCFunctionWithKeywords)meth)(self, args, kwds);
|
||||
}
|
||||
else if (flags == METH_FASTCALL) {
|
||||
PyObject **stack = &PyTuple_GET_ITEM(args, 0);
|
||||
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
|
||||
res = _PyCFunction_FastCallDict(func, stack, nargs, kwds);
|
||||
}
|
||||
else {
|
||||
if (kwds != NULL && PyDict_Size(kwds) != 0) {
|
||||
PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
|
||||
f->m_ml->ml_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (flags) {
|
||||
case METH_VARARGS:
|
||||
res = (*meth)(self, args);
|
||||
break;
|
||||
|
||||
case METH_NOARGS:
|
||||
size = PyTuple_GET_SIZE(args);
|
||||
if (size != 0) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s() takes no arguments (%zd given)",
|
||||
f->m_ml->ml_name, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = (*meth)(self, NULL);
|
||||
break;
|
||||
|
||||
case METH_O:
|
||||
size = PyTuple_GET_SIZE(args);
|
||||
if (size != 1) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s() takes exactly one argument (%zd given)",
|
||||
f->m_ml->ml_name, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
arg = PyTuple_GET_ITEM(args, 0);
|
||||
res = (*meth)(self, arg);
|
||||
break;
|
||||
|
||||
default:
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Bad call flags in PyCFunction_Call. "
|
||||
"METH_OLDARGS is no longer supported!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return _Py_CheckFunctionResult(func, res, NULL);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs,
|
||||
PyObject *kwargs)
|
||||
{
|
||||
PyCFunctionObject *func = (PyCFunctionObject*)func_obj;
|
||||
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
|
||||
PyObject *self = PyCFunction_GET_SELF(func);
|
||||
PyObject *result;
|
||||
int flags;
|
||||
|
||||
assert(PyCFunction_Check(func));
|
||||
assert(func != NULL);
|
||||
assert(nargs >= 0);
|
||||
assert(nargs == 0 || args != NULL);
|
||||
assert(kwargs == NULL || PyDict_Check(kwargs));
|
||||
|
||||
/* _PyCFunction_FastCallDict() must not be called with an exception set,
|
||||
because it may clear it (directly or indirectly) and so the
|
||||
caller loses its exception */
|
||||
assert(!PyErr_Occurred());
|
||||
|
||||
flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
|
||||
|
||||
switch (flags)
|
||||
{
|
||||
case METH_NOARGS:
|
||||
if (kwargs != NULL && PyDict_Size(kwargs) != 0) {
|
||||
PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
|
||||
func->m_ml->ml_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (nargs != 0) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s() takes no arguments (%zd given)",
|
||||
func->m_ml->ml_name, nargs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = (*meth) (self, NULL);
|
||||
break;
|
||||
|
||||
case METH_O:
|
||||
if (kwargs != NULL && PyDict_Size(kwargs) != 0) {
|
||||
PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
|
||||
func->m_ml->ml_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (nargs != 1) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s() takes exactly one argument (%zd given)",
|
||||
func->m_ml->ml_name, nargs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = (*meth) (self, args[0]);
|
||||
break;
|
||||
|
||||
case METH_VARARGS:
|
||||
case METH_VARARGS | METH_KEYWORDS:
|
||||
{
|
||||
/* Slow-path: create a temporary tuple */
|
||||
PyObject *tuple;
|
||||
|
||||
if (!(flags & METH_KEYWORDS) && kwargs != NULL && PyDict_Size(kwargs) != 0) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s() takes no keyword arguments",
|
||||
func->m_ml->ml_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tuple = _PyStack_AsTuple(args, nargs);
|
||||
if (tuple == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (flags & METH_KEYWORDS) {
|
||||
result = (*(PyCFunctionWithKeywords)meth) (self, tuple, kwargs);
|
||||
}
|
||||
else {
|
||||
result = (*meth) (self, tuple);
|
||||
}
|
||||
Py_DECREF(tuple);
|
||||
break;
|
||||
}
|
||||
|
||||
case METH_FASTCALL:
|
||||
{
|
||||
PyObject **stack;
|
||||
PyObject *kwnames;
|
||||
_PyCFunctionFast fastmeth = (_PyCFunctionFast)meth;
|
||||
|
||||
if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = (*fastmeth) (self, stack, nargs, kwnames);
|
||||
if (stack != args) {
|
||||
PyMem_Free(stack);
|
||||
}
|
||||
Py_XDECREF(kwnames);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Bad call flags in PyCFunction_Call. "
|
||||
"METH_OLDARGS is no longer supported!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = _Py_CheckFunctionResult(func_obj, result, NULL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyCFunction_FastCallKeywords(PyObject *func, PyObject **stack,
|
||||
Py_ssize_t nargs, PyObject *kwnames)
|
||||
{
|
||||
PyObject *kwdict, *result;
|
||||
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
|
||||
|
||||
assert(PyCFunction_Check(func));
|
||||
assert(nargs >= 0);
|
||||
assert(kwnames == NULL || PyTuple_CheckExact(kwnames));
|
||||
assert((nargs == 0 && nkwargs == 0) || stack != NULL);
|
||||
/* kwnames must only contains str strings, no subclass, and all keys must
|
||||
be unique */
|
||||
|
||||
if (nkwargs > 0) {
|
||||
kwdict = _PyStack_AsDict(stack + nargs, kwnames);
|
||||
if (kwdict == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
kwdict = NULL;
|
||||
}
|
||||
|
||||
result = _PyCFunction_FastCallDict(func, stack, nargs, kwdict);
|
||||
Py_XDECREF(kwdict);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Methods (the standard built-in methods, that is) */
|
||||
|
||||
static void
|
||||
meth_dealloc(PyCFunctionObject *m)
|
||||
{
|
||||
_PyObject_GC_UNTRACK(m);
|
||||
if (m->m_weakreflist != NULL) {
|
||||
PyObject_ClearWeakRefs((PyObject*) m);
|
||||
}
|
||||
Py_XDECREF(m->m_self);
|
||||
Py_XDECREF(m->m_module);
|
||||
if (numfree < PyCFunction_MAXFREELIST) {
|
||||
m->m_self = (PyObject *)free_list;
|
||||
free_list = m;
|
||||
numfree++;
|
||||
}
|
||||
else {
|
||||
PyObject_GC_Del(m);
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
meth_reduce(PyCFunctionObject *m)
|
||||
{
|
||||
_Py_IDENTIFIER(getattr);
|
||||
|
||||
if (m->m_self == NULL || PyModule_Check(m->m_self))
|
||||
return PyUnicode_FromString(m->m_ml->ml_name);
|
||||
|
||||
return Py_BuildValue("N(Os)", _PyEval_GetBuiltinId(&PyId_getattr),
|
||||
m->m_self, m->m_ml->ml_name);
|
||||
}
|
||||
|
||||
static PyMethodDef meth_methods[] = {
|
||||
{"__reduce__", (PyCFunction)meth_reduce, METH_NOARGS, NULL},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
meth_get__text_signature__(PyCFunctionObject *m, void *closure)
|
||||
{
|
||||
return _PyType_GetTextSignatureFromInternalDoc(m->m_ml->ml_name, m->m_ml->ml_doc);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
meth_get__doc__(PyCFunctionObject *m, void *closure)
|
||||
{
|
||||
return _PyType_GetDocFromInternalDoc(m->m_ml->ml_name, m->m_ml->ml_doc);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
meth_get__name__(PyCFunctionObject *m, void *closure)
|
||||
{
|
||||
return PyUnicode_FromString(m->m_ml->ml_name);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
meth_get__qualname__(PyCFunctionObject *m, void *closure)
|
||||
{
|
||||
/* If __self__ is a module or NULL, return m.__name__
|
||||
(e.g. len.__qualname__ == 'len')
|
||||
|
||||
If __self__ is a type, return m.__self__.__qualname__ + '.' + m.__name__
|
||||
(e.g. dict.fromkeys.__qualname__ == 'dict.fromkeys')
|
||||
|
||||
Otherwise return type(m.__self__).__qualname__ + '.' + m.__name__
|
||||
(e.g. [].append.__qualname__ == 'list.append') */
|
||||
PyObject *type, *type_qualname, *res;
|
||||
_Py_IDENTIFIER(__qualname__);
|
||||
|
||||
if (m->m_self == NULL || PyModule_Check(m->m_self))
|
||||
return PyUnicode_FromString(m->m_ml->ml_name);
|
||||
|
||||
type = PyType_Check(m->m_self) ? m->m_self : (PyObject*)Py_TYPE(m->m_self);
|
||||
|
||||
type_qualname = _PyObject_GetAttrId(type, &PyId___qualname__);
|
||||
if (type_qualname == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!PyUnicode_Check(type_qualname)) {
|
||||
PyErr_SetString(PyExc_TypeError, "<method>.__class__."
|
||||
"__qualname__ is not a unicode object");
|
||||
Py_XDECREF(type_qualname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = PyUnicode_FromFormat("%S.%s", type_qualname, m->m_ml->ml_name);
|
||||
Py_DECREF(type_qualname);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(m->m_self);
|
||||
Py_VISIT(m->m_module);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
meth_get__self__(PyCFunctionObject *m, void *closure)
|
||||
{
|
||||
PyObject *self;
|
||||
|
||||
self = PyCFunction_GET_SELF(m);
|
||||
if (self == NULL)
|
||||
self = Py_None;
|
||||
Py_INCREF(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
static PyGetSetDef meth_getsets [] = {
|
||||
{"__doc__", (getter)meth_get__doc__, NULL, NULL},
|
||||
{"__name__", (getter)meth_get__name__, NULL, NULL},
|
||||
{"__qualname__", (getter)meth_get__qualname__, NULL, NULL},
|
||||
{"__self__", (getter)meth_get__self__, NULL, NULL},
|
||||
{"__text_signature__", (getter)meth_get__text_signature__, NULL, NULL},
|
||||
{0}
|
||||
};
|
||||
|
||||
#define OFF(x) offsetof(PyCFunctionObject, x)
|
||||
|
||||
static PyMemberDef meth_members[] = {
|
||||
{"__module__", T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
meth_repr(PyCFunctionObject *m)
|
||||
{
|
||||
if (m->m_self == NULL || PyModule_Check(m->m_self))
|
||||
return PyUnicode_FromFormat("<built-in function %s>",
|
||||
m->m_ml->ml_name);
|
||||
return PyUnicode_FromFormat("<built-in method %s of %s object at %p>",
|
||||
m->m_ml->ml_name,
|
||||
m->m_self->ob_type->tp_name,
|
||||
m->m_self);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
meth_richcompare(PyObject *self, PyObject *other, int op)
|
||||
{
|
||||
PyCFunctionObject *a, *b;
|
||||
PyObject *res;
|
||||
int eq;
|
||||
|
||||
if ((op != Py_EQ && op != Py_NE) ||
|
||||
!PyCFunction_Check(self) ||
|
||||
!PyCFunction_Check(other))
|
||||
{
|
||||
Py_RETURN_NOTIMPLEMENTED;
|
||||
}
|
||||
a = (PyCFunctionObject *)self;
|
||||
b = (PyCFunctionObject *)other;
|
||||
eq = a->m_self == b->m_self;
|
||||
if (eq)
|
||||
eq = a->m_ml->ml_meth == b->m_ml->ml_meth;
|
||||
if (op == Py_EQ)
|
||||
res = eq ? Py_True : Py_False;
|
||||
else
|
||||
res = eq ? Py_False : Py_True;
|
||||
Py_INCREF(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static Py_hash_t
|
||||
meth_hash(PyCFunctionObject *a)
|
||||
{
|
||||
Py_hash_t x, y;
|
||||
if (a->m_self == NULL)
|
||||
x = 0;
|
||||
else {
|
||||
x = PyObject_Hash(a->m_self);
|
||||
if (x == -1)
|
||||
return -1;
|
||||
}
|
||||
y = _Py_HashPointer((void*)(a->m_ml->ml_meth));
|
||||
if (y == -1)
|
||||
return -1;
|
||||
x ^= y;
|
||||
if (x == -1)
|
||||
x = -2;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
PyTypeObject PyCFunction_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"builtin_function_or_method",
|
||||
sizeof(PyCFunctionObject),
|
||||
0,
|
||||
(destructor)meth_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
(reprfunc)meth_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
(hashfunc)meth_hash, /* tp_hash */
|
||||
PyCFunction_Call, /* tp_call */
|
||||
0, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc)meth_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
meth_richcompare, /* tp_richcompare */
|
||||
offsetof(PyCFunctionObject, m_weakreflist), /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
meth_methods, /* tp_methods */
|
||||
meth_members, /* tp_members */
|
||||
meth_getsets, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
};
|
||||
|
||||
/* Clear out the free list */
|
||||
|
||||
int
|
||||
PyCFunction_ClearFreeList(void)
|
||||
{
|
||||
int freelist_size = numfree;
|
||||
|
||||
while (free_list) {
|
||||
PyCFunctionObject *v = free_list;
|
||||
free_list = (PyCFunctionObject *)(v->m_self);
|
||||
PyObject_GC_Del(v);
|
||||
numfree--;
|
||||
}
|
||||
assert(numfree == 0);
|
||||
return freelist_size;
|
||||
}
|
||||
|
||||
void
|
||||
PyCFunction_Fini(void)
|
||||
{
|
||||
(void)PyCFunction_ClearFreeList();
|
||||
}
|
||||
|
||||
/* Print summary info about the state of the optimized allocator */
|
||||
void
|
||||
_PyCFunction_DebugMallocStats(FILE *out)
|
||||
{
|
||||
_PyDebugAllocatorStats(out,
|
||||
"free PyCFunctionObject",
|
||||
numfree, sizeof(PyCFunctionObject));
|
||||
}
|
802
third_party/python/Objects/moduleobject.c
vendored
Normal file
802
third_party/python/Objects/moduleobject.c
vendored
Normal file
|
@ -0,0 +1,802 @@
|
|||
|
||||
/* Module object implementation */
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
|
||||
static Py_ssize_t max_module_number;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *md_dict;
|
||||
struct PyModuleDef *md_def;
|
||||
void *md_state;
|
||||
PyObject *md_weaklist;
|
||||
PyObject *md_name; /* for logging purposes after md_dict is cleared */
|
||||
} PyModuleObject;
|
||||
|
||||
static PyMemberDef module_members[] = {
|
||||
{"__dict__", T_OBJECT, offsetof(PyModuleObject, md_dict), READONLY},
|
||||
{0}
|
||||
};
|
||||
|
||||
|
||||
/* Helper for sanity check for traverse not handling m_state == NULL
|
||||
* Issue #32374 */
|
||||
#ifdef Py_DEBUG
|
||||
static int
|
||||
bad_traverse_test(PyObject *self, void *arg) {
|
||||
assert(self != NULL);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
PyTypeObject PyModuleDef_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"moduledef", /* tp_name */
|
||||
sizeof(struct PyModuleDef), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
};
|
||||
|
||||
|
||||
PyObject*
|
||||
PyModuleDef_Init(struct PyModuleDef* def)
|
||||
{
|
||||
if (PyType_Ready(&PyModuleDef_Type) < 0)
|
||||
return NULL;
|
||||
if (def->m_base.m_index == 0) {
|
||||
max_module_number++;
|
||||
Py_REFCNT(def) = 1;
|
||||
Py_TYPE(def) = &PyModuleDef_Type;
|
||||
def->m_base.m_index = max_module_number;
|
||||
}
|
||||
return (PyObject*)def;
|
||||
}
|
||||
|
||||
static int
|
||||
module_init_dict(PyModuleObject *mod, PyObject *md_dict,
|
||||
PyObject *name, PyObject *doc)
|
||||
{
|
||||
_Py_IDENTIFIER(__name__);
|
||||
_Py_IDENTIFIER(__doc__);
|
||||
_Py_IDENTIFIER(__package__);
|
||||
_Py_IDENTIFIER(__loader__);
|
||||
_Py_IDENTIFIER(__spec__);
|
||||
|
||||
if (md_dict == NULL)
|
||||
return -1;
|
||||
if (doc == NULL)
|
||||
doc = Py_None;
|
||||
|
||||
if (_PyDict_SetItemId(md_dict, &PyId___name__, name) != 0)
|
||||
return -1;
|
||||
if (_PyDict_SetItemId(md_dict, &PyId___doc__, doc) != 0)
|
||||
return -1;
|
||||
if (_PyDict_SetItemId(md_dict, &PyId___package__, Py_None) != 0)
|
||||
return -1;
|
||||
if (_PyDict_SetItemId(md_dict, &PyId___loader__, Py_None) != 0)
|
||||
return -1;
|
||||
if (_PyDict_SetItemId(md_dict, &PyId___spec__, Py_None) != 0)
|
||||
return -1;
|
||||
if (PyUnicode_CheckExact(name)) {
|
||||
Py_INCREF(name);
|
||||
Py_XSETREF(mod->md_name, name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
PyModule_NewObject(PyObject *name)
|
||||
{
|
||||
PyModuleObject *m;
|
||||
m = PyObject_GC_New(PyModuleObject, &PyModule_Type);
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
m->md_def = NULL;
|
||||
m->md_state = NULL;
|
||||
m->md_weaklist = NULL;
|
||||
m->md_name = NULL;
|
||||
m->md_dict = PyDict_New();
|
||||
if (module_init_dict(m, m->md_dict, name, NULL) != 0)
|
||||
goto fail;
|
||||
PyObject_GC_Track(m);
|
||||
return (PyObject *)m;
|
||||
|
||||
fail:
|
||||
Py_DECREF(m);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyModule_New(const char *name)
|
||||
{
|
||||
PyObject *nameobj, *module;
|
||||
nameobj = PyUnicode_FromString(name);
|
||||
if (nameobj == NULL)
|
||||
return NULL;
|
||||
module = PyModule_NewObject(nameobj);
|
||||
Py_DECREF(nameobj);
|
||||
return module;
|
||||
}
|
||||
|
||||
/* Check API/ABI version
|
||||
* Issues a warning on mismatch, which is usually not fatal.
|
||||
* Returns 0 if an exception is raised.
|
||||
*/
|
||||
static int
|
||||
check_api_version(const char *name, int module_api_version)
|
||||
{
|
||||
if (module_api_version != PYTHON_API_VERSION && module_api_version != PYTHON_ABI_VERSION) {
|
||||
int err;
|
||||
err = PyErr_WarnFormat(PyExc_RuntimeWarning, 1,
|
||||
"Python C API version mismatch for module %.100s: "
|
||||
"This Python has API version %d, module %.100s has version %d.",
|
||||
name,
|
||||
PYTHON_API_VERSION, name, module_api_version);
|
||||
if (err)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_add_methods_to_object(PyObject *module, PyObject *name, PyMethodDef *functions)
|
||||
{
|
||||
PyObject *func;
|
||||
PyMethodDef *fdef;
|
||||
|
||||
for (fdef = functions; fdef->ml_name != NULL; fdef++) {
|
||||
if ((fdef->ml_flags & METH_CLASS) ||
|
||||
(fdef->ml_flags & METH_STATIC)) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"module functions cannot set"
|
||||
" METH_CLASS or METH_STATIC");
|
||||
return -1;
|
||||
}
|
||||
func = PyCFunction_NewEx(fdef, (PyObject*)module, name);
|
||||
if (func == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (PyObject_SetAttrString(module, fdef->ml_name, func) != 0) {
|
||||
Py_DECREF(func);
|
||||
return -1;
|
||||
}
|
||||
Py_DECREF(func);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyModule_Create2(struct PyModuleDef* module, int module_api_version)
|
||||
{
|
||||
const char* name;
|
||||
PyModuleObject *m;
|
||||
PyInterpreterState *interp = PyThreadState_Get()->interp;
|
||||
if (interp->modules == NULL)
|
||||
Py_FatalError("Python import machinery not initialized");
|
||||
if (!PyModuleDef_Init(module))
|
||||
return NULL;
|
||||
name = module->m_name;
|
||||
if (!check_api_version(name, module_api_version)) {
|
||||
return NULL;
|
||||
}
|
||||
if (module->m_slots) {
|
||||
PyErr_Format(
|
||||
PyExc_SystemError,
|
||||
"module %s: PyModule_Create is incompatible with m_slots", name);
|
||||
return NULL;
|
||||
}
|
||||
/* Make sure name is fully qualified.
|
||||
|
||||
This is a bit of a hack: when the shared library is loaded,
|
||||
the module name is "package.module", but the module calls
|
||||
PyModule_Create*() with just "module" for the name. The shared
|
||||
library loader squirrels away the true name of the module in
|
||||
_Py_PackageContext, and PyModule_Create*() will substitute this
|
||||
(if the name actually matches).
|
||||
*/
|
||||
if (_Py_PackageContext != NULL) {
|
||||
char *p = strrchr(_Py_PackageContext, '.');
|
||||
if (p != NULL && strcmp(module->m_name, p+1) == 0) {
|
||||
name = _Py_PackageContext;
|
||||
_Py_PackageContext = NULL;
|
||||
}
|
||||
}
|
||||
if ((m = (PyModuleObject*)PyModule_New(name)) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (module->m_size > 0) {
|
||||
m->md_state = PyMem_MALLOC(module->m_size);
|
||||
if (!m->md_state) {
|
||||
PyErr_NoMemory();
|
||||
Py_DECREF(m);
|
||||
return NULL;
|
||||
}
|
||||
memset(m->md_state, 0, module->m_size);
|
||||
}
|
||||
|
||||
if (module->m_methods != NULL) {
|
||||
if (PyModule_AddFunctions((PyObject *) m, module->m_methods) != 0) {
|
||||
Py_DECREF(m);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (module->m_doc != NULL) {
|
||||
if (PyModule_SetDocString((PyObject *) m, module->m_doc) != 0) {
|
||||
Py_DECREF(m);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
m->md_def = module;
|
||||
return (PyObject*)m;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyModule_FromDefAndSpec2(struct PyModuleDef* def, PyObject *spec, int module_api_version)
|
||||
{
|
||||
PyModuleDef_Slot* cur_slot;
|
||||
PyObject *(*create)(PyObject *, PyModuleDef*) = NULL;
|
||||
PyObject *nameobj;
|
||||
PyObject *m = NULL;
|
||||
int has_execution_slots = 0;
|
||||
char *name;
|
||||
int ret;
|
||||
|
||||
PyModuleDef_Init(def);
|
||||
|
||||
nameobj = PyObject_GetAttrString(spec, "name");
|
||||
if (nameobj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
name = PyUnicode_AsUTF8(nameobj);
|
||||
if (name == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!check_api_version(name, module_api_version)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (def->m_size < 0) {
|
||||
PyErr_Format(
|
||||
PyExc_SystemError,
|
||||
"module %s: m_size may not be negative for multi-phase initialization",
|
||||
name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (cur_slot = def->m_slots; cur_slot && cur_slot->slot; cur_slot++) {
|
||||
if (cur_slot->slot == Py_mod_create) {
|
||||
if (create) {
|
||||
PyErr_Format(
|
||||
PyExc_SystemError,
|
||||
"module %s has multiple create slots",
|
||||
name);
|
||||
goto error;
|
||||
}
|
||||
create = cur_slot->value;
|
||||
} else if (cur_slot->slot < 0 || cur_slot->slot > _Py_mod_LAST_SLOT) {
|
||||
PyErr_Format(
|
||||
PyExc_SystemError,
|
||||
"module %s uses unknown slot ID %i",
|
||||
name, cur_slot->slot);
|
||||
goto error;
|
||||
} else {
|
||||
has_execution_slots = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (create) {
|
||||
m = create(spec, def);
|
||||
if (m == NULL) {
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_Format(
|
||||
PyExc_SystemError,
|
||||
"creation of module %s failed without setting an exception",
|
||||
name);
|
||||
}
|
||||
goto error;
|
||||
} else {
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
"creation of module %s raised unreported exception",
|
||||
name);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m = PyModule_NewObject(nameobj);
|
||||
if (m == NULL) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (PyModule_Check(m)) {
|
||||
((PyModuleObject*)m)->md_state = NULL;
|
||||
((PyModuleObject*)m)->md_def = def;
|
||||
} else {
|
||||
if (def->m_size > 0 || def->m_traverse || def->m_clear || def->m_free) {
|
||||
PyErr_Format(
|
||||
PyExc_SystemError,
|
||||
"module %s is not a module object, but requests module state",
|
||||
name);
|
||||
goto error;
|
||||
}
|
||||
if (has_execution_slots) {
|
||||
PyErr_Format(
|
||||
PyExc_SystemError,
|
||||
"module %s specifies execution slots, but did not create "
|
||||
"a ModuleType instance",
|
||||
name);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (def->m_methods != NULL) {
|
||||
ret = _add_methods_to_object(m, nameobj, def->m_methods);
|
||||
if (ret != 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (def->m_doc != NULL) {
|
||||
ret = PyModule_SetDocString(m, def->m_doc);
|
||||
if (ret != 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sanity check for traverse not handling m_state == NULL
|
||||
* This doesn't catch all possible cases, but in many cases it should
|
||||
* make many cases of invalid code crash or raise Valgrind issues
|
||||
* sooner than they would otherwise.
|
||||
* Issue #32374 */
|
||||
#ifdef Py_DEBUG
|
||||
if (def->m_traverse != NULL) {
|
||||
def->m_traverse(m, bad_traverse_test, NULL);
|
||||
}
|
||||
#endif
|
||||
Py_DECREF(nameobj);
|
||||
return m;
|
||||
|
||||
error:
|
||||
Py_DECREF(nameobj);
|
||||
Py_XDECREF(m);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
PyModule_ExecDef(PyObject *module, PyModuleDef *def)
|
||||
{
|
||||
PyModuleDef_Slot *cur_slot;
|
||||
const char *name;
|
||||
int ret;
|
||||
|
||||
name = PyModule_GetName(module);
|
||||
if (name == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (def->m_size >= 0) {
|
||||
PyModuleObject *md = (PyModuleObject*)module;
|
||||
if (md->md_state == NULL) {
|
||||
/* Always set a state pointer; this serves as a marker to skip
|
||||
* multiple initialization (importlib.reload() is no-op) */
|
||||
md->md_state = PyMem_MALLOC(def->m_size);
|
||||
if (!md->md_state) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
memset(md->md_state, 0, def->m_size);
|
||||
}
|
||||
}
|
||||
|
||||
if (def->m_slots == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (cur_slot = def->m_slots; cur_slot && cur_slot->slot; cur_slot++) {
|
||||
switch (cur_slot->slot) {
|
||||
case Py_mod_create:
|
||||
/* handled in PyModule_FromDefAndSpec2 */
|
||||
break;
|
||||
case Py_mod_exec:
|
||||
ret = ((int (*)(PyObject *))cur_slot->value)(module);
|
||||
if (ret != 0) {
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_Format(
|
||||
PyExc_SystemError,
|
||||
"execution of module %s failed without setting an exception",
|
||||
name);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_Format(
|
||||
PyExc_SystemError,
|
||||
"execution of module %s raised unreported exception",
|
||||
name);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PyErr_Format(
|
||||
PyExc_SystemError,
|
||||
"module %s initialized with unknown slot %i",
|
||||
name, cur_slot->slot);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
PyModule_AddFunctions(PyObject *m, PyMethodDef *functions)
|
||||
{
|
||||
int res;
|
||||
PyObject *name = PyModule_GetNameObject(m);
|
||||
if (name == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = _add_methods_to_object(m, name, functions);
|
||||
Py_DECREF(name);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
PyModule_SetDocString(PyObject *m, const char *doc)
|
||||
{
|
||||
PyObject *v;
|
||||
_Py_IDENTIFIER(__doc__);
|
||||
|
||||
v = PyUnicode_FromString(doc);
|
||||
if (v == NULL || _PyObject_SetAttrId(m, &PyId___doc__, v) != 0) {
|
||||
Py_XDECREF(v);
|
||||
return -1;
|
||||
}
|
||||
Py_DECREF(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyModule_GetDict(PyObject *m)
|
||||
{
|
||||
PyObject *d;
|
||||
if (!PyModule_Check(m)) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
d = ((PyModuleObject *)m) -> md_dict;
|
||||
assert(d != NULL);
|
||||
return d;
|
||||
}
|
||||
|
||||
PyObject*
|
||||
PyModule_GetNameObject(PyObject *m)
|
||||
{
|
||||
_Py_IDENTIFIER(__name__);
|
||||
PyObject *d;
|
||||
PyObject *name;
|
||||
if (!PyModule_Check(m)) {
|
||||
PyErr_BadArgument();
|
||||
return NULL;
|
||||
}
|
||||
d = ((PyModuleObject *)m)->md_dict;
|
||||
if (d == NULL ||
|
||||
(name = _PyDict_GetItemId(d, &PyId___name__)) == NULL ||
|
||||
!PyUnicode_Check(name))
|
||||
{
|
||||
PyErr_SetString(PyExc_SystemError, "nameless module");
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(name);
|
||||
return name;
|
||||
}
|
||||
|
||||
const char *
|
||||
PyModule_GetName(PyObject *m)
|
||||
{
|
||||
PyObject *name = PyModule_GetNameObject(m);
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
Py_DECREF(name); /* module dict has still a reference */
|
||||
return PyUnicode_AsUTF8(name);
|
||||
}
|
||||
|
||||
PyObject*
|
||||
PyModule_GetFilenameObject(PyObject *m)
|
||||
{
|
||||
_Py_IDENTIFIER(__file__);
|
||||
PyObject *d;
|
||||
PyObject *fileobj;
|
||||
if (!PyModule_Check(m)) {
|
||||
PyErr_BadArgument();
|
||||
return NULL;
|
||||
}
|
||||
d = ((PyModuleObject *)m)->md_dict;
|
||||
if (d == NULL ||
|
||||
(fileobj = _PyDict_GetItemId(d, &PyId___file__)) == NULL ||
|
||||
!PyUnicode_Check(fileobj))
|
||||
{
|
||||
PyErr_SetString(PyExc_SystemError, "module filename missing");
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(fileobj);
|
||||
return fileobj;
|
||||
}
|
||||
|
||||
const char *
|
||||
PyModule_GetFilename(PyObject *m)
|
||||
{
|
||||
PyObject *fileobj;
|
||||
char *utf8;
|
||||
fileobj = PyModule_GetFilenameObject(m);
|
||||
if (fileobj == NULL)
|
||||
return NULL;
|
||||
utf8 = PyUnicode_AsUTF8(fileobj);
|
||||
Py_DECREF(fileobj); /* module dict has still a reference */
|
||||
return utf8;
|
||||
}
|
||||
|
||||
PyModuleDef*
|
||||
PyModule_GetDef(PyObject* m)
|
||||
{
|
||||
if (!PyModule_Check(m)) {
|
||||
PyErr_BadArgument();
|
||||
return NULL;
|
||||
}
|
||||
return ((PyModuleObject *)m)->md_def;
|
||||
}
|
||||
|
||||
void*
|
||||
PyModule_GetState(PyObject* m)
|
||||
{
|
||||
if (!PyModule_Check(m)) {
|
||||
PyErr_BadArgument();
|
||||
return NULL;
|
||||
}
|
||||
return ((PyModuleObject *)m)->md_state;
|
||||
}
|
||||
|
||||
void
|
||||
_PyModule_Clear(PyObject *m)
|
||||
{
|
||||
PyObject *d = ((PyModuleObject *)m)->md_dict;
|
||||
if (d != NULL)
|
||||
_PyModule_ClearDict(d);
|
||||
}
|
||||
|
||||
void
|
||||
_PyModule_ClearDict(PyObject *d)
|
||||
{
|
||||
/* To make the execution order of destructors for global
|
||||
objects a bit more predictable, we first zap all objects
|
||||
whose name starts with a single underscore, before we clear
|
||||
the entire dictionary. We zap them by replacing them with
|
||||
None, rather than deleting them from the dictionary, to
|
||||
avoid rehashing the dictionary (to some extent). */
|
||||
|
||||
Py_ssize_t pos;
|
||||
PyObject *key, *value;
|
||||
|
||||
/* First, clear only names starting with a single underscore */
|
||||
pos = 0;
|
||||
while (PyDict_Next(d, &pos, &key, &value)) {
|
||||
if (value != Py_None && PyUnicode_Check(key)) {
|
||||
if (PyUnicode_READ_CHAR(key, 0) == '_' &&
|
||||
PyUnicode_READ_CHAR(key, 1) != '_') {
|
||||
if (Py_VerboseFlag > 1) {
|
||||
const char *s = PyUnicode_AsUTF8(key);
|
||||
if (s != NULL)
|
||||
PySys_WriteStderr("# clear[1] %s\n", s);
|
||||
else
|
||||
PyErr_Clear();
|
||||
}
|
||||
if (PyDict_SetItem(d, key, Py_None) != 0)
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Next, clear all names except for __builtins__ */
|
||||
pos = 0;
|
||||
while (PyDict_Next(d, &pos, &key, &value)) {
|
||||
if (value != Py_None && PyUnicode_Check(key)) {
|
||||
if (PyUnicode_READ_CHAR(key, 0) != '_' ||
|
||||
!_PyUnicode_EqualToASCIIString(key, "__builtins__"))
|
||||
{
|
||||
if (Py_VerboseFlag > 1) {
|
||||
const char *s = PyUnicode_AsUTF8(key);
|
||||
if (s != NULL)
|
||||
PySys_WriteStderr("# clear[2] %s\n", s);
|
||||
else
|
||||
PyErr_Clear();
|
||||
}
|
||||
if (PyDict_SetItem(d, key, Py_None) != 0)
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: we leave __builtins__ in place, so that destructors
|
||||
of non-global objects defined in this module can still use
|
||||
builtins, in particularly 'None'. */
|
||||
|
||||
}
|
||||
|
||||
/* Methods */
|
||||
|
||||
static int
|
||||
module_init(PyModuleObject *m, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static char *kwlist[] = {"name", "doc", NULL};
|
||||
PyObject *dict, *name = Py_None, *doc = Py_None;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "U|O:module.__init__",
|
||||
kwlist, &name, &doc))
|
||||
return -1;
|
||||
dict = m->md_dict;
|
||||
if (dict == NULL) {
|
||||
dict = PyDict_New();
|
||||
if (dict == NULL)
|
||||
return -1;
|
||||
m->md_dict = dict;
|
||||
}
|
||||
if (module_init_dict(m, dict, name, doc) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
module_dealloc(PyModuleObject *m)
|
||||
{
|
||||
PyObject_GC_UnTrack(m);
|
||||
if (Py_VerboseFlag && m->md_name) {
|
||||
PySys_FormatStderr("# destroy %S\n", m->md_name);
|
||||
}
|
||||
if (m->md_weaklist != NULL)
|
||||
PyObject_ClearWeakRefs((PyObject *) m);
|
||||
if (m->md_def && m->md_def->m_free)
|
||||
m->md_def->m_free(m);
|
||||
Py_XDECREF(m->md_dict);
|
||||
Py_XDECREF(m->md_name);
|
||||
if (m->md_state != NULL)
|
||||
PyMem_FREE(m->md_state);
|
||||
Py_TYPE(m)->tp_free((PyObject *)m);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
module_repr(PyModuleObject *m)
|
||||
{
|
||||
PyThreadState *tstate = PyThreadState_GET();
|
||||
PyInterpreterState *interp = tstate->interp;
|
||||
|
||||
return PyObject_CallMethod(interp->importlib, "_module_repr", "O", m);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
module_getattro(PyModuleObject *m, PyObject *name)
|
||||
{
|
||||
PyObject *attr, *mod_name;
|
||||
attr = PyObject_GenericGetAttr((PyObject *)m, name);
|
||||
if (attr || !PyErr_ExceptionMatches(PyExc_AttributeError))
|
||||
return attr;
|
||||
PyErr_Clear();
|
||||
if (m->md_dict) {
|
||||
_Py_IDENTIFIER(__name__);
|
||||
mod_name = _PyDict_GetItemId(m->md_dict, &PyId___name__);
|
||||
if (mod_name && PyUnicode_Check(mod_name)) {
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"module '%U' has no attribute '%U'", mod_name, name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"module has no attribute '%U'", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
module_traverse(PyModuleObject *m, visitproc visit, void *arg)
|
||||
{
|
||||
if (m->md_def && m->md_def->m_traverse) {
|
||||
int res = m->md_def->m_traverse((PyObject*)m, visit, arg);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
Py_VISIT(m->md_dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
module_clear(PyModuleObject *m)
|
||||
{
|
||||
if (m->md_def && m->md_def->m_clear) {
|
||||
int res = m->md_def->m_clear((PyObject*)m);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
Py_CLEAR(m->md_dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
module_dir(PyObject *self, PyObject *args)
|
||||
{
|
||||
_Py_IDENTIFIER(__dict__);
|
||||
PyObject *result = NULL;
|
||||
PyObject *dict = _PyObject_GetAttrId(self, &PyId___dict__);
|
||||
|
||||
if (dict != NULL) {
|
||||
if (PyDict_Check(dict))
|
||||
result = PyDict_Keys(dict);
|
||||
else {
|
||||
const char *name = PyModule_GetName(self);
|
||||
if (name)
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s.__dict__ is not a dictionary",
|
||||
name);
|
||||
}
|
||||
}
|
||||
|
||||
Py_XDECREF(dict);
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"__dir__", module_dir, METH_NOARGS,
|
||||
PyDoc_STR("__dir__() -> list\nspecialized dir() implementation")},
|
||||
{0}
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(module_doc,
|
||||
"module(name[, doc])\n\
|
||||
\n\
|
||||
Create a module object.\n\
|
||||
The name must be a string; the optional doc argument can have any type.");
|
||||
|
||||
PyTypeObject PyModule_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"module", /* tp_name */
|
||||
sizeof(PyModuleObject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)module_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
(reprfunc)module_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
(getattrofunc)module_getattro, /* tp_getattro */
|
||||
PyObject_GenericSetAttr, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
|
||||
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
module_doc, /* tp_doc */
|
||||
(traverseproc)module_traverse, /* tp_traverse */
|
||||
(inquiry)module_clear, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
offsetof(PyModuleObject, md_weaklist), /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
module_methods, /* tp_methods */
|
||||
module_members, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
offsetof(PyModuleObject, md_dict), /* tp_dictoffset */
|
||||
(initproc)module_init, /* tp_init */
|
||||
PyType_GenericAlloc, /* tp_alloc */
|
||||
PyType_GenericNew, /* tp_new */
|
||||
PyObject_GC_Del, /* tp_free */
|
||||
};
|
266
third_party/python/Objects/namespaceobject.c
vendored
Normal file
266
third_party/python/Objects/namespaceobject.c
vendored
Normal file
|
@ -0,0 +1,266 @@
|
|||
// namespace object implementation
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *ns_dict;
|
||||
} _PyNamespaceObject;
|
||||
|
||||
|
||||
static PyMemberDef namespace_members[] = {
|
||||
{"__dict__", T_OBJECT, offsetof(_PyNamespaceObject, ns_dict), READONLY},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
// Methods
|
||||
|
||||
static PyObject *
|
||||
namespace_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *self;
|
||||
|
||||
assert(type != NULL && type->tp_alloc != NULL);
|
||||
self = type->tp_alloc(type, 0);
|
||||
if (self != NULL) {
|
||||
_PyNamespaceObject *ns = (_PyNamespaceObject *)self;
|
||||
ns->ns_dict = PyDict_New();
|
||||
if (ns->ns_dict == NULL) {
|
||||
Py_DECREF(ns);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
namespace_init(_PyNamespaceObject *ns, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
// ignore args if it's NULL or empty
|
||||
if (args != NULL) {
|
||||
Py_ssize_t argcount = PyObject_Size(args);
|
||||
if (argcount < 0)
|
||||
return -1;
|
||||
else if (argcount > 0) {
|
||||
PyErr_Format(PyExc_TypeError, "no positional arguments expected");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (kwds == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (!PyArg_ValidateKeywordArguments(kwds)) {
|
||||
return -1;
|
||||
}
|
||||
return PyDict_Update(ns->ns_dict, kwds);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
namespace_dealloc(_PyNamespaceObject *ns)
|
||||
{
|
||||
PyObject_GC_UnTrack(ns);
|
||||
Py_CLEAR(ns->ns_dict);
|
||||
Py_TYPE(ns)->tp_free((PyObject *)ns);
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
namespace_repr(PyObject *ns)
|
||||
{
|
||||
int i, loop_error = 0;
|
||||
PyObject *pairs = NULL, *d = NULL, *keys = NULL, *keys_iter = NULL;
|
||||
PyObject *key;
|
||||
PyObject *separator, *pairsrepr, *repr = NULL;
|
||||
const char * name;
|
||||
|
||||
name = (Py_TYPE(ns) == &_PyNamespace_Type) ? "namespace"
|
||||
: ns->ob_type->tp_name;
|
||||
|
||||
i = Py_ReprEnter(ns);
|
||||
if (i != 0) {
|
||||
return i > 0 ? PyUnicode_FromFormat("%s(...)", name) : NULL;
|
||||
}
|
||||
|
||||
pairs = PyList_New(0);
|
||||
if (pairs == NULL)
|
||||
goto error;
|
||||
|
||||
d = ((_PyNamespaceObject *)ns)->ns_dict;
|
||||
assert(d != NULL);
|
||||
Py_INCREF(d);
|
||||
|
||||
keys = PyDict_Keys(d);
|
||||
if (keys == NULL)
|
||||
goto error;
|
||||
if (PyList_Sort(keys) != 0)
|
||||
goto error;
|
||||
|
||||
keys_iter = PyObject_GetIter(keys);
|
||||
if (keys_iter == NULL)
|
||||
goto error;
|
||||
|
||||
while ((key = PyIter_Next(keys_iter)) != NULL) {
|
||||
if (PyUnicode_Check(key) && PyUnicode_GET_LENGTH(key) > 0) {
|
||||
PyObject *value, *item;
|
||||
|
||||
value = PyDict_GetItem(d, key);
|
||||
if (value != NULL) {
|
||||
item = PyUnicode_FromFormat("%S=%R", key, value);
|
||||
if (item == NULL) {
|
||||
loop_error = 1;
|
||||
}
|
||||
else {
|
||||
loop_error = PyList_Append(pairs, item);
|
||||
Py_DECREF(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Py_DECREF(key);
|
||||
if (loop_error)
|
||||
goto error;
|
||||
}
|
||||
|
||||
separator = PyUnicode_FromString(", ");
|
||||
if (separator == NULL)
|
||||
goto error;
|
||||
|
||||
pairsrepr = PyUnicode_Join(separator, pairs);
|
||||
Py_DECREF(separator);
|
||||
if (pairsrepr == NULL)
|
||||
goto error;
|
||||
|
||||
repr = PyUnicode_FromFormat("%s(%S)", name, pairsrepr);
|
||||
Py_DECREF(pairsrepr);
|
||||
|
||||
error:
|
||||
Py_XDECREF(pairs);
|
||||
Py_XDECREF(d);
|
||||
Py_XDECREF(keys);
|
||||
Py_XDECREF(keys_iter);
|
||||
Py_ReprLeave(ns);
|
||||
|
||||
return repr;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
namespace_traverse(_PyNamespaceObject *ns, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(ns->ns_dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
namespace_clear(_PyNamespaceObject *ns)
|
||||
{
|
||||
Py_CLEAR(ns->ns_dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
namespace_richcompare(PyObject *self, PyObject *other, int op)
|
||||
{
|
||||
if (PyObject_TypeCheck(self, &_PyNamespace_Type) &&
|
||||
PyObject_TypeCheck(other, &_PyNamespace_Type))
|
||||
return PyObject_RichCompare(((_PyNamespaceObject *)self)->ns_dict,
|
||||
((_PyNamespaceObject *)other)->ns_dict, op);
|
||||
Py_RETURN_NOTIMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(namespace_reduce__doc__, "Return state information for pickling");
|
||||
|
||||
static PyObject *
|
||||
namespace_reduce(_PyNamespaceObject *ns)
|
||||
{
|
||||
PyObject *result, *args = PyTuple_New(0);
|
||||
|
||||
if (!args)
|
||||
return NULL;
|
||||
|
||||
result = PyTuple_Pack(3, (PyObject *)Py_TYPE(ns), args, ns->ns_dict);
|
||||
Py_DECREF(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef namespace_methods[] = {
|
||||
{"__reduce__", (PyCFunction)namespace_reduce, METH_NOARGS,
|
||||
namespace_reduce__doc__},
|
||||
{NULL, NULL} // sentinel
|
||||
};
|
||||
|
||||
|
||||
PyDoc_STRVAR(namespace_doc,
|
||||
"A simple attribute-based namespace.\n\
|
||||
\n\
|
||||
SimpleNamespace(**kwargs)");
|
||||
|
||||
PyTypeObject _PyNamespace_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"types.SimpleNamespace", /* tp_name */
|
||||
sizeof(_PyNamespaceObject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)namespace_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
(reprfunc)namespace_repr, /* 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 */
|
||||
PyObject_GenericSetAttr, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
|
||||
Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
namespace_doc, /* tp_doc */
|
||||
(traverseproc)namespace_traverse, /* tp_traverse */
|
||||
(inquiry)namespace_clear, /* tp_clear */
|
||||
namespace_richcompare, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
namespace_methods, /* tp_methods */
|
||||
namespace_members, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
offsetof(_PyNamespaceObject, ns_dict), /* tp_dictoffset */
|
||||
(initproc)namespace_init, /* tp_init */
|
||||
PyType_GenericAlloc, /* tp_alloc */
|
||||
(newfunc)namespace_new, /* tp_new */
|
||||
PyObject_GC_Del, /* tp_free */
|
||||
};
|
||||
|
||||
|
||||
PyObject *
|
||||
_PyNamespace_New(PyObject *kwds)
|
||||
{
|
||||
PyObject *ns = namespace_new(&_PyNamespace_Type, NULL, NULL);
|
||||
if (ns == NULL)
|
||||
return NULL;
|
||||
|
||||
if (kwds == NULL)
|
||||
return ns;
|
||||
if (PyDict_Update(((_PyNamespaceObject *)ns)->ns_dict, kwds) != 0) {
|
||||
Py_DECREF(ns);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (PyObject *)ns;
|
||||
}
|
2080
third_party/python/Objects/object.c
vendored
Normal file
2080
third_party/python/Objects/object.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
2412
third_party/python/Objects/obmalloc.c
vendored
Normal file
2412
third_party/python/Objects/obmalloc.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
2388
third_party/python/Objects/odictobject.c
vendored
Normal file
2388
third_party/python/Objects/odictobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
1298
third_party/python/Objects/rangeobject.c
vendored
Normal file
1298
third_party/python/Objects/rangeobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
2574
third_party/python/Objects/setobject.c
vendored
Normal file
2574
third_party/python/Objects/setobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
671
third_party/python/Objects/sliceobject.c
vendored
Normal file
671
third_party/python/Objects/sliceobject.c
vendored
Normal file
|
@ -0,0 +1,671 @@
|
|||
/*
|
||||
Written by Jim Hugunin and Chris Chase.
|
||||
|
||||
This includes both the singular ellipsis object and slice objects.
|
||||
|
||||
Guido, feel free to do whatever you want in the way of copyrights
|
||||
for this file.
|
||||
*/
|
||||
|
||||
/*
|
||||
Py_Ellipsis encodes the '...' rubber index token. It is similar to
|
||||
the Py_NoneStruct in that there is no way to create other objects of
|
||||
this type and there is exactly one in existence.
|
||||
*/
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
|
||||
static PyObject *
|
||||
ellipsis_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_Size(kwargs))) {
|
||||
PyErr_SetString(PyExc_TypeError, "EllipsisType takes no arguments");
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(Py_Ellipsis);
|
||||
return Py_Ellipsis;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
ellipsis_repr(PyObject *op)
|
||||
{
|
||||
return PyUnicode_FromString("Ellipsis");
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
ellipsis_reduce(PyObject *op)
|
||||
{
|
||||
return PyUnicode_FromString("Ellipsis");
|
||||
}
|
||||
|
||||
static PyMethodDef ellipsis_methods[] = {
|
||||
{"__reduce__", (PyCFunction)ellipsis_reduce, METH_NOARGS, NULL},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
PyTypeObject PyEllipsis_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"ellipsis", /* tp_name */
|
||||
0, /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
0, /*never called*/ /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
ellipsis_repr, /* 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 */
|
||||
0, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
ellipsis_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
ellipsis_new, /* tp_new */
|
||||
};
|
||||
|
||||
PyObject _Py_EllipsisObject = {
|
||||
_PyObject_EXTRA_INIT
|
||||
1, &PyEllipsis_Type
|
||||
};
|
||||
|
||||
|
||||
/* Slice object implementation */
|
||||
|
||||
/* Using a cache is very effective since typically only a single slice is
|
||||
* created and then deleted again
|
||||
*/
|
||||
static PySliceObject *slice_cache = NULL;
|
||||
void PySlice_Fini(void)
|
||||
{
|
||||
PySliceObject *obj = slice_cache;
|
||||
if (obj != NULL) {
|
||||
slice_cache = NULL;
|
||||
PyObject_GC_Del(obj);
|
||||
}
|
||||
}
|
||||
|
||||
/* start, stop, and step are python objects with None indicating no
|
||||
index is present.
|
||||
*/
|
||||
|
||||
PyObject *
|
||||
PySlice_New(PyObject *start, PyObject *stop, PyObject *step)
|
||||
{
|
||||
PySliceObject *obj;
|
||||
if (slice_cache != NULL) {
|
||||
obj = slice_cache;
|
||||
slice_cache = NULL;
|
||||
_Py_NewReference((PyObject *)obj);
|
||||
} else {
|
||||
obj = PyObject_GC_New(PySliceObject, &PySlice_Type);
|
||||
if (obj == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (step == NULL) step = Py_None;
|
||||
Py_INCREF(step);
|
||||
if (start == NULL) start = Py_None;
|
||||
Py_INCREF(start);
|
||||
if (stop == NULL) stop = Py_None;
|
||||
Py_INCREF(stop);
|
||||
|
||||
obj->step = step;
|
||||
obj->start = start;
|
||||
obj->stop = stop;
|
||||
|
||||
_PyObject_GC_TRACK(obj);
|
||||
return (PyObject *) obj;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop)
|
||||
{
|
||||
PyObject *start, *end, *slice;
|
||||
start = PyLong_FromSsize_t(istart);
|
||||
if (!start)
|
||||
return NULL;
|
||||
end = PyLong_FromSsize_t(istop);
|
||||
if (!end) {
|
||||
Py_DECREF(start);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
slice = PySlice_New(start, end, NULL);
|
||||
Py_DECREF(start);
|
||||
Py_DECREF(end);
|
||||
return slice;
|
||||
}
|
||||
|
||||
int
|
||||
PySlice_GetIndices(PyObject *_r, Py_ssize_t length,
|
||||
Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
|
||||
{
|
||||
PySliceObject *r = (PySliceObject*)_r;
|
||||
/* XXX support long ints */
|
||||
if (r->step == Py_None) {
|
||||
*step = 1;
|
||||
} else {
|
||||
if (!PyLong_Check(r->step)) return -1;
|
||||
*step = PyLong_AsSsize_t(r->step);
|
||||
}
|
||||
if (r->start == Py_None) {
|
||||
*start = *step < 0 ? length-1 : 0;
|
||||
} else {
|
||||
if (!PyLong_Check(r->start)) return -1;
|
||||
*start = PyLong_AsSsize_t(r->start);
|
||||
if (*start < 0) *start += length;
|
||||
}
|
||||
if (r->stop == Py_None) {
|
||||
*stop = *step < 0 ? -1 : length;
|
||||
} else {
|
||||
if (!PyLong_Check(r->stop)) return -1;
|
||||
*stop = PyLong_AsSsize_t(r->stop);
|
||||
if (*stop < 0) *stop += length;
|
||||
}
|
||||
if (*stop > length) return -1;
|
||||
if (*start >= length) return -1;
|
||||
if (*step == 0) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
PySlice_Unpack(PyObject *_r,
|
||||
Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
|
||||
{
|
||||
PySliceObject *r = (PySliceObject*)_r;
|
||||
/* this is harder to get right than you might think */
|
||||
|
||||
Py_BUILD_ASSERT(PY_SSIZE_T_MIN + 1 <= -PY_SSIZE_T_MAX);
|
||||
|
||||
if (r->step == Py_None) {
|
||||
*step = 1;
|
||||
}
|
||||
else {
|
||||
if (!_PyEval_SliceIndex(r->step, step)) return -1;
|
||||
if (*step == 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"slice step cannot be zero");
|
||||
return -1;
|
||||
}
|
||||
/* Here *step might be -PY_SSIZE_T_MAX-1; in this case we replace it
|
||||
* with -PY_SSIZE_T_MAX. This doesn't affect the semantics, and it
|
||||
* guards against later undefined behaviour resulting from code that
|
||||
* does "step = -step" as part of a slice reversal.
|
||||
*/
|
||||
if (*step < -PY_SSIZE_T_MAX)
|
||||
*step = -PY_SSIZE_T_MAX;
|
||||
}
|
||||
|
||||
if (r->start == Py_None) {
|
||||
*start = *step < 0 ? PY_SSIZE_T_MAX : 0;
|
||||
}
|
||||
else {
|
||||
if (!_PyEval_SliceIndex(r->start, start)) return -1;
|
||||
}
|
||||
|
||||
if (r->stop == Py_None) {
|
||||
*stop = *step < 0 ? PY_SSIZE_T_MIN : PY_SSIZE_T_MAX;
|
||||
}
|
||||
else {
|
||||
if (!_PyEval_SliceIndex(r->stop, stop)) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Py_ssize_t
|
||||
PySlice_AdjustIndices(Py_ssize_t length,
|
||||
Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t step)
|
||||
{
|
||||
/* this is harder to get right than you might think */
|
||||
|
||||
assert(step != 0);
|
||||
assert(step >= -PY_SSIZE_T_MAX);
|
||||
|
||||
if (*start < 0) {
|
||||
*start += length;
|
||||
if (*start < 0) {
|
||||
*start = (step < 0) ? -1 : 0;
|
||||
}
|
||||
}
|
||||
else if (*start >= length) {
|
||||
*start = (step < 0) ? length - 1 : length;
|
||||
}
|
||||
|
||||
if (*stop < 0) {
|
||||
*stop += length;
|
||||
if (*stop < 0) {
|
||||
*stop = (step < 0) ? -1 : 0;
|
||||
}
|
||||
}
|
||||
else if (*stop >= length) {
|
||||
*stop = (step < 0) ? length - 1 : length;
|
||||
}
|
||||
|
||||
if (step < 0) {
|
||||
if (*stop < *start) {
|
||||
return (*start - *stop - 1) / (-step) + 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (*start < *stop) {
|
||||
return (*stop - *start - 1) / step + 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef PySlice_GetIndicesEx
|
||||
|
||||
int
|
||||
PySlice_GetIndicesEx(PyObject *_r, Py_ssize_t length,
|
||||
Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step,
|
||||
Py_ssize_t *slicelength)
|
||||
{
|
||||
if (PySlice_Unpack(_r, start, stop, step) < 0)
|
||||
return -1;
|
||||
*slicelength = PySlice_AdjustIndices(length, start, stop, *step);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
slice_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||
{
|
||||
PyObject *start, *stop, *step;
|
||||
|
||||
start = stop = step = NULL;
|
||||
|
||||
if (!_PyArg_NoKeywords("slice()", kw))
|
||||
return NULL;
|
||||
|
||||
if (!PyArg_UnpackTuple(args, "slice", 1, 3, &start, &stop, &step))
|
||||
return NULL;
|
||||
|
||||
/* This swapping of stop and start is to maintain similarity with
|
||||
range(). */
|
||||
if (stop == NULL) {
|
||||
stop = start;
|
||||
start = NULL;
|
||||
}
|
||||
return PySlice_New(start, stop, step);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(slice_doc,
|
||||
"slice(stop)\n\
|
||||
slice(start, stop[, step])\n\
|
||||
\n\
|
||||
Create a slice object. This is used for extended slicing (e.g. a[0:10:2]).");
|
||||
|
||||
static void
|
||||
slice_dealloc(PySliceObject *r)
|
||||
{
|
||||
_PyObject_GC_UNTRACK(r);
|
||||
Py_DECREF(r->step);
|
||||
Py_DECREF(r->start);
|
||||
Py_DECREF(r->stop);
|
||||
if (slice_cache == NULL)
|
||||
slice_cache = r;
|
||||
else
|
||||
PyObject_GC_Del(r);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
slice_repr(PySliceObject *r)
|
||||
{
|
||||
return PyUnicode_FromFormat("slice(%R, %R, %R)", r->start, r->stop, r->step);
|
||||
}
|
||||
|
||||
static PyMemberDef slice_members[] = {
|
||||
{"start", T_OBJECT, offsetof(PySliceObject, start), READONLY},
|
||||
{"stop", T_OBJECT, offsetof(PySliceObject, stop), READONLY},
|
||||
{"step", T_OBJECT, offsetof(PySliceObject, step), READONLY},
|
||||
{0}
|
||||
};
|
||||
|
||||
/* Helper function to convert a slice argument to a PyLong, and raise TypeError
|
||||
with a suitable message on failure. */
|
||||
|
||||
static PyObject*
|
||||
evaluate_slice_index(PyObject *v)
|
||||
{
|
||||
if (PyIndex_Check(v)) {
|
||||
return PyNumber_Index(v);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"slice indices must be integers or "
|
||||
"None or have an __index__ method");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute slice indices given a slice and length. Return -1 on failure. Used
|
||||
by slice.indices and rangeobject slicing. Assumes that `len` is a
|
||||
nonnegative instance of PyLong. */
|
||||
|
||||
int
|
||||
_PySlice_GetLongIndices(PySliceObject *self, PyObject *length,
|
||||
PyObject **start_ptr, PyObject **stop_ptr,
|
||||
PyObject **step_ptr)
|
||||
{
|
||||
PyObject *start=NULL, *stop=NULL, *step=NULL;
|
||||
PyObject *upper=NULL, *lower=NULL;
|
||||
int step_is_negative, cmp_result;
|
||||
|
||||
/* Convert step to an integer; raise for zero step. */
|
||||
if (self->step == Py_None) {
|
||||
step = PyLong_FromLong(1L);
|
||||
if (step == NULL)
|
||||
goto error;
|
||||
step_is_negative = 0;
|
||||
}
|
||||
else {
|
||||
int step_sign;
|
||||
step = evaluate_slice_index(self->step);
|
||||
if (step == NULL)
|
||||
goto error;
|
||||
step_sign = _PyLong_Sign(step);
|
||||
if (step_sign == 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"slice step cannot be zero");
|
||||
goto error;
|
||||
}
|
||||
step_is_negative = step_sign < 0;
|
||||
}
|
||||
|
||||
/* Find lower and upper bounds for start and stop. */
|
||||
if (step_is_negative) {
|
||||
lower = PyLong_FromLong(-1L);
|
||||
if (lower == NULL)
|
||||
goto error;
|
||||
|
||||
upper = PyNumber_Add(length, lower);
|
||||
if (upper == NULL)
|
||||
goto error;
|
||||
}
|
||||
else {
|
||||
lower = PyLong_FromLong(0L);
|
||||
if (lower == NULL)
|
||||
goto error;
|
||||
|
||||
upper = length;
|
||||
Py_INCREF(upper);
|
||||
}
|
||||
|
||||
/* Compute start. */
|
||||
if (self->start == Py_None) {
|
||||
start = step_is_negative ? upper : lower;
|
||||
Py_INCREF(start);
|
||||
}
|
||||
else {
|
||||
start = evaluate_slice_index(self->start);
|
||||
if (start == NULL)
|
||||
goto error;
|
||||
|
||||
if (_PyLong_Sign(start) < 0) {
|
||||
/* start += length */
|
||||
PyObject *tmp = PyNumber_Add(start, length);
|
||||
Py_DECREF(start);
|
||||
start = tmp;
|
||||
if (start == NULL)
|
||||
goto error;
|
||||
|
||||
cmp_result = PyObject_RichCompareBool(start, lower, Py_LT);
|
||||
if (cmp_result < 0)
|
||||
goto error;
|
||||
if (cmp_result) {
|
||||
Py_INCREF(lower);
|
||||
Py_DECREF(start);
|
||||
start = lower;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cmp_result = PyObject_RichCompareBool(start, upper, Py_GT);
|
||||
if (cmp_result < 0)
|
||||
goto error;
|
||||
if (cmp_result) {
|
||||
Py_INCREF(upper);
|
||||
Py_DECREF(start);
|
||||
start = upper;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute stop. */
|
||||
if (self->stop == Py_None) {
|
||||
stop = step_is_negative ? lower : upper;
|
||||
Py_INCREF(stop);
|
||||
}
|
||||
else {
|
||||
stop = evaluate_slice_index(self->stop);
|
||||
if (stop == NULL)
|
||||
goto error;
|
||||
|
||||
if (_PyLong_Sign(stop) < 0) {
|
||||
/* stop += length */
|
||||
PyObject *tmp = PyNumber_Add(stop, length);
|
||||
Py_DECREF(stop);
|
||||
stop = tmp;
|
||||
if (stop == NULL)
|
||||
goto error;
|
||||
|
||||
cmp_result = PyObject_RichCompareBool(stop, lower, Py_LT);
|
||||
if (cmp_result < 0)
|
||||
goto error;
|
||||
if (cmp_result) {
|
||||
Py_INCREF(lower);
|
||||
Py_DECREF(stop);
|
||||
stop = lower;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cmp_result = PyObject_RichCompareBool(stop, upper, Py_GT);
|
||||
if (cmp_result < 0)
|
||||
goto error;
|
||||
if (cmp_result) {
|
||||
Py_INCREF(upper);
|
||||
Py_DECREF(stop);
|
||||
stop = upper;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*start_ptr = start;
|
||||
*stop_ptr = stop;
|
||||
*step_ptr = step;
|
||||
Py_DECREF(upper);
|
||||
Py_DECREF(lower);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
*start_ptr = *stop_ptr = *step_ptr = NULL;
|
||||
Py_XDECREF(start);
|
||||
Py_XDECREF(stop);
|
||||
Py_XDECREF(step);
|
||||
Py_XDECREF(upper);
|
||||
Py_XDECREF(lower);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Implementation of slice.indices. */
|
||||
|
||||
static PyObject*
|
||||
slice_indices(PySliceObject* self, PyObject* len)
|
||||
{
|
||||
PyObject *start, *stop, *step;
|
||||
PyObject *length;
|
||||
int error;
|
||||
|
||||
/* Convert length to an integer if necessary; raise for negative length. */
|
||||
length = PyNumber_Index(len);
|
||||
if (length == NULL)
|
||||
return NULL;
|
||||
|
||||
if (_PyLong_Sign(length) < 0) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"length should not be negative");
|
||||
Py_DECREF(length);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
error = _PySlice_GetLongIndices(self, length, &start, &stop, &step);
|
||||
Py_DECREF(length);
|
||||
if (error == -1)
|
||||
return NULL;
|
||||
else
|
||||
return Py_BuildValue("(NNN)", start, stop, step);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(slice_indices_doc,
|
||||
"S.indices(len) -> (start, stop, stride)\n\
|
||||
\n\
|
||||
Assuming a sequence of length len, calculate the start and stop\n\
|
||||
indices, and the stride length of the extended slice described by\n\
|
||||
S. Out of bounds indices are clipped in a manner consistent with the\n\
|
||||
handling of normal slices.");
|
||||
|
||||
static PyObject *
|
||||
slice_reduce(PySliceObject* self)
|
||||
{
|
||||
return Py_BuildValue("O(OOO)", Py_TYPE(self), self->start, self->stop, self->step);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
|
||||
|
||||
static PyMethodDef slice_methods[] = {
|
||||
{"indices", (PyCFunction)slice_indices,
|
||||
METH_O, slice_indices_doc},
|
||||
{"__reduce__", (PyCFunction)slice_reduce,
|
||||
METH_NOARGS, reduce_doc},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
slice_richcompare(PyObject *v, PyObject *w, int op)
|
||||
{
|
||||
PyObject *t1;
|
||||
PyObject *t2;
|
||||
PyObject *res;
|
||||
|
||||
if (!PySlice_Check(v) || !PySlice_Check(w))
|
||||
Py_RETURN_NOTIMPLEMENTED;
|
||||
|
||||
if (v == w) {
|
||||
/* XXX Do we really need this shortcut?
|
||||
There's a unit test for it, but is that fair? */
|
||||
switch (op) {
|
||||
case Py_EQ:
|
||||
case Py_LE:
|
||||
case Py_GE:
|
||||
res = Py_True;
|
||||
break;
|
||||
default:
|
||||
res = Py_False;
|
||||
break;
|
||||
}
|
||||
Py_INCREF(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
t1 = PyTuple_New(3);
|
||||
if (t1 == NULL)
|
||||
return NULL;
|
||||
t2 = PyTuple_New(3);
|
||||
if (t2 == NULL) {
|
||||
Py_DECREF(t1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyTuple_SET_ITEM(t1, 0, ((PySliceObject *)v)->start);
|
||||
PyTuple_SET_ITEM(t1, 1, ((PySliceObject *)v)->stop);
|
||||
PyTuple_SET_ITEM(t1, 2, ((PySliceObject *)v)->step);
|
||||
PyTuple_SET_ITEM(t2, 0, ((PySliceObject *)w)->start);
|
||||
PyTuple_SET_ITEM(t2, 1, ((PySliceObject *)w)->stop);
|
||||
PyTuple_SET_ITEM(t2, 2, ((PySliceObject *)w)->step);
|
||||
|
||||
res = PyObject_RichCompare(t1, t2, op);
|
||||
|
||||
PyTuple_SET_ITEM(t1, 0, NULL);
|
||||
PyTuple_SET_ITEM(t1, 1, NULL);
|
||||
PyTuple_SET_ITEM(t1, 2, NULL);
|
||||
PyTuple_SET_ITEM(t2, 0, NULL);
|
||||
PyTuple_SET_ITEM(t2, 1, NULL);
|
||||
PyTuple_SET_ITEM(t2, 2, NULL);
|
||||
|
||||
Py_DECREF(t1);
|
||||
Py_DECREF(t2);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
slice_traverse(PySliceObject *v, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(v->start);
|
||||
Py_VISIT(v->stop);
|
||||
Py_VISIT(v->step);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyTypeObject PySlice_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"slice", /* Name of this type */
|
||||
sizeof(PySliceObject), /* Basic object size */
|
||||
0, /* Item size for varobject */
|
||||
(destructor)slice_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
(reprfunc)slice_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
PyObject_HashNotImplemented, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
slice_doc, /* tp_doc */
|
||||
(traverseproc)slice_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
slice_richcompare, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
slice_methods, /* tp_methods */
|
||||
slice_members, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
slice_new, /* tp_new */
|
||||
};
|
40
third_party/python/Objects/stringlib/README.txt
vendored
Normal file
40
third_party/python/Objects/stringlib/README.txt
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
bits shared by the bytesobject and unicodeobject implementations (and
|
||||
possibly other modules, in a not too distant future).
|
||||
|
||||
the stuff in here is included into relevant places; see the individual
|
||||
source files for details.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
the following defines used by the different modules:
|
||||
|
||||
STRINGLIB_CHAR
|
||||
|
||||
the type used to hold a character (char or Py_UNICODE)
|
||||
|
||||
STRINGLIB_EMPTY
|
||||
|
||||
a PyObject representing the empty string, only to be used if
|
||||
STRINGLIB_MUTABLE is 0
|
||||
|
||||
Py_ssize_t STRINGLIB_LEN(PyObject*)
|
||||
|
||||
returns the length of the given string object (which must be of the
|
||||
right type)
|
||||
|
||||
PyObject* STRINGLIB_NEW(STRINGLIB_CHAR*, Py_ssize_t)
|
||||
|
||||
creates a new string object
|
||||
|
||||
STRINGLIB_CHAR* STRINGLIB_STR(PyObject*)
|
||||
|
||||
returns the pointer to the character data for the given string
|
||||
object (which must be of the right type)
|
||||
|
||||
int STRINGLIB_CHECK_EXACT(PyObject *)
|
||||
|
||||
returns true if the object is an instance of our type, not a subclass
|
||||
|
||||
STRINGLIB_MUTABLE
|
||||
|
||||
must be 0 or 1 to tell the cpp macros in stringlib code if the object
|
||||
being operated on is mutable or not
|
29
third_party/python/Objects/stringlib/asciilib.h
vendored
Normal file
29
third_party/python/Objects/stringlib/asciilib.h
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* this is sort of a hack. there's at least one place (formatting
|
||||
floats) where some stringlib code takes a different path if it's
|
||||
compiled as unicode. */
|
||||
#define STRINGLIB_IS_UNICODE 1
|
||||
|
||||
#define FASTSEARCH asciilib_fastsearch
|
||||
#define STRINGLIB(F) asciilib_##F
|
||||
#define STRINGLIB_OBJECT PyUnicodeObject
|
||||
#define STRINGLIB_SIZEOF_CHAR 1
|
||||
#define STRINGLIB_MAX_CHAR 0x7Fu
|
||||
#define STRINGLIB_CHAR Py_UCS1
|
||||
#define STRINGLIB_TYPE_NAME "unicode"
|
||||
#define STRINGLIB_PARSE_CODE "U"
|
||||
#define STRINGLIB_EMPTY unicode_empty
|
||||
#define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE
|
||||
#define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK
|
||||
#define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL
|
||||
#define STRINGLIB_TODECIMAL Py_UNICODE_TODECIMAL
|
||||
#define STRINGLIB_STR PyUnicode_1BYTE_DATA
|
||||
#define STRINGLIB_LEN PyUnicode_GET_LENGTH
|
||||
#define STRINGLIB_NEW(STR,LEN) _PyUnicode_FromASCII((char*)(STR),(LEN))
|
||||
#define STRINGLIB_CHECK PyUnicode_Check
|
||||
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
|
||||
|
||||
#define STRINGLIB_TOSTR PyObject_Str
|
||||
#define STRINGLIB_TOASCII PyObject_ASCII
|
||||
|
||||
#define _Py_InsertThousandsGrouping _PyUnicode_ascii_InsertThousandsGrouping
|
||||
|
822
third_party/python/Objects/stringlib/codecs.h
vendored
Normal file
822
third_party/python/Objects/stringlib/codecs.h
vendored
Normal file
|
@ -0,0 +1,822 @@
|
|||
/* stringlib: codec implementations */
|
||||
|
||||
#if !STRINGLIB_IS_UNICODE
|
||||
# error "codecs.h is specific to Unicode"
|
||||
#endif
|
||||
|
||||
/* Mask to quickly check whether a C 'long' contains a
|
||||
non-ASCII, UTF8-encoded char. */
|
||||
#if (SIZEOF_LONG == 8)
|
||||
# define ASCII_CHAR_MASK 0x8080808080808080UL
|
||||
#elif (SIZEOF_LONG == 4)
|
||||
# define ASCII_CHAR_MASK 0x80808080UL
|
||||
#else
|
||||
# error C 'long' size should be either 4 or 8!
|
||||
#endif
|
||||
|
||||
/* 10xxxxxx */
|
||||
#define IS_CONTINUATION_BYTE(ch) ((ch) >= 0x80 && (ch) < 0xC0)
|
||||
|
||||
Py_LOCAL_INLINE(Py_UCS4)
|
||||
STRINGLIB(utf8_decode)(const char **inptr, const char *end,
|
||||
STRINGLIB_CHAR *dest,
|
||||
Py_ssize_t *outpos)
|
||||
{
|
||||
Py_UCS4 ch;
|
||||
const char *s = *inptr;
|
||||
const char *aligned_end = (const char *) _Py_ALIGN_DOWN(end, SIZEOF_LONG);
|
||||
STRINGLIB_CHAR *p = dest + *outpos;
|
||||
|
||||
while (s < end) {
|
||||
ch = (unsigned char)*s;
|
||||
|
||||
if (ch < 0x80) {
|
||||
/* Fast path for runs of ASCII characters. Given that common UTF-8
|
||||
input will consist of an overwhelming majority of ASCII
|
||||
characters, we try to optimize for this case by checking
|
||||
as many characters as a C 'long' can contain.
|
||||
First, check if we can do an aligned read, as most CPUs have
|
||||
a penalty for unaligned reads.
|
||||
*/
|
||||
if (_Py_IS_ALIGNED(s, SIZEOF_LONG)) {
|
||||
/* Help register allocation */
|
||||
const char *_s = s;
|
||||
STRINGLIB_CHAR *_p = p;
|
||||
while (_s < aligned_end) {
|
||||
/* Read a whole long at a time (either 4 or 8 bytes),
|
||||
and do a fast unrolled copy if it only contains ASCII
|
||||
characters. */
|
||||
unsigned long value = *(unsigned long *) _s;
|
||||
if (value & ASCII_CHAR_MASK)
|
||||
break;
|
||||
#if PY_LITTLE_ENDIAN
|
||||
_p[0] = (STRINGLIB_CHAR)(value & 0xFFu);
|
||||
_p[1] = (STRINGLIB_CHAR)((value >> 8) & 0xFFu);
|
||||
_p[2] = (STRINGLIB_CHAR)((value >> 16) & 0xFFu);
|
||||
_p[3] = (STRINGLIB_CHAR)((value >> 24) & 0xFFu);
|
||||
# if SIZEOF_LONG == 8
|
||||
_p[4] = (STRINGLIB_CHAR)((value >> 32) & 0xFFu);
|
||||
_p[5] = (STRINGLIB_CHAR)((value >> 40) & 0xFFu);
|
||||
_p[6] = (STRINGLIB_CHAR)((value >> 48) & 0xFFu);
|
||||
_p[7] = (STRINGLIB_CHAR)((value >> 56) & 0xFFu);
|
||||
# endif
|
||||
#else
|
||||
# if SIZEOF_LONG == 8
|
||||
_p[0] = (STRINGLIB_CHAR)((value >> 56) & 0xFFu);
|
||||
_p[1] = (STRINGLIB_CHAR)((value >> 48) & 0xFFu);
|
||||
_p[2] = (STRINGLIB_CHAR)((value >> 40) & 0xFFu);
|
||||
_p[3] = (STRINGLIB_CHAR)((value >> 32) & 0xFFu);
|
||||
_p[4] = (STRINGLIB_CHAR)((value >> 24) & 0xFFu);
|
||||
_p[5] = (STRINGLIB_CHAR)((value >> 16) & 0xFFu);
|
||||
_p[6] = (STRINGLIB_CHAR)((value >> 8) & 0xFFu);
|
||||
_p[7] = (STRINGLIB_CHAR)(value & 0xFFu);
|
||||
# else
|
||||
_p[0] = (STRINGLIB_CHAR)((value >> 24) & 0xFFu);
|
||||
_p[1] = (STRINGLIB_CHAR)((value >> 16) & 0xFFu);
|
||||
_p[2] = (STRINGLIB_CHAR)((value >> 8) & 0xFFu);
|
||||
_p[3] = (STRINGLIB_CHAR)(value & 0xFFu);
|
||||
# endif
|
||||
#endif
|
||||
_s += SIZEOF_LONG;
|
||||
_p += SIZEOF_LONG;
|
||||
}
|
||||
s = _s;
|
||||
p = _p;
|
||||
if (s == end)
|
||||
break;
|
||||
ch = (unsigned char)*s;
|
||||
}
|
||||
if (ch < 0x80) {
|
||||
s++;
|
||||
*p++ = ch;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch < 0xE0) {
|
||||
/* \xC2\x80-\xDF\xBF -- 0080-07FF */
|
||||
Py_UCS4 ch2;
|
||||
if (ch < 0xC2) {
|
||||
/* invalid sequence
|
||||
\x80-\xBF -- continuation byte
|
||||
\xC0-\xC1 -- fake 0000-007F */
|
||||
goto InvalidStart;
|
||||
}
|
||||
if (end - s < 2) {
|
||||
/* unexpected end of data: the caller will decide whether
|
||||
it's an error or not */
|
||||
break;
|
||||
}
|
||||
ch2 = (unsigned char)s[1];
|
||||
if (!IS_CONTINUATION_BYTE(ch2))
|
||||
/* invalid continuation byte */
|
||||
goto InvalidContinuation1;
|
||||
ch = (ch << 6) + ch2 -
|
||||
((0xC0 << 6) + 0x80);
|
||||
assert ((ch > 0x007F) && (ch <= 0x07FF));
|
||||
s += 2;
|
||||
if (STRINGLIB_MAX_CHAR <= 0x007F ||
|
||||
(STRINGLIB_MAX_CHAR < 0x07FF && ch > STRINGLIB_MAX_CHAR))
|
||||
/* Out-of-range */
|
||||
goto Return;
|
||||
*p++ = ch;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch < 0xF0) {
|
||||
/* \xE0\xA0\x80-\xEF\xBF\xBF -- 0800-FFFF */
|
||||
Py_UCS4 ch2, ch3;
|
||||
if (end - s < 3) {
|
||||
/* unexpected end of data: the caller will decide whether
|
||||
it's an error or not */
|
||||
if (end - s < 2)
|
||||
break;
|
||||
ch2 = (unsigned char)s[1];
|
||||
if (!IS_CONTINUATION_BYTE(ch2) ||
|
||||
(ch2 < 0xA0 ? ch == 0xE0 : ch == 0xED))
|
||||
/* for clarification see comments below */
|
||||
goto InvalidContinuation1;
|
||||
break;
|
||||
}
|
||||
ch2 = (unsigned char)s[1];
|
||||
ch3 = (unsigned char)s[2];
|
||||
if (!IS_CONTINUATION_BYTE(ch2)) {
|
||||
/* invalid continuation byte */
|
||||
goto InvalidContinuation1;
|
||||
}
|
||||
if (ch == 0xE0) {
|
||||
if (ch2 < 0xA0)
|
||||
/* invalid sequence
|
||||
\xE0\x80\x80-\xE0\x9F\xBF -- fake 0000-0800 */
|
||||
goto InvalidContinuation1;
|
||||
} else if (ch == 0xED && ch2 >= 0xA0) {
|
||||
/* Decoding UTF-8 sequences in range \xED\xA0\x80-\xED\xBF\xBF
|
||||
will result in surrogates in range D800-DFFF. Surrogates are
|
||||
not valid UTF-8 so they are rejected.
|
||||
See http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf
|
||||
(table 3-7) and http://www.rfc-editor.org/rfc/rfc3629.txt */
|
||||
goto InvalidContinuation1;
|
||||
}
|
||||
if (!IS_CONTINUATION_BYTE(ch3)) {
|
||||
/* invalid continuation byte */
|
||||
goto InvalidContinuation2;
|
||||
}
|
||||
ch = (ch << 12) + (ch2 << 6) + ch3 -
|
||||
((0xE0 << 12) + (0x80 << 6) + 0x80);
|
||||
assert ((ch > 0x07FF) && (ch <= 0xFFFF));
|
||||
s += 3;
|
||||
if (STRINGLIB_MAX_CHAR <= 0x07FF ||
|
||||
(STRINGLIB_MAX_CHAR < 0xFFFF && ch > STRINGLIB_MAX_CHAR))
|
||||
/* Out-of-range */
|
||||
goto Return;
|
||||
*p++ = ch;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch < 0xF5) {
|
||||
/* \xF0\x90\x80\x80-\xF4\x8F\xBF\xBF -- 10000-10FFFF */
|
||||
Py_UCS4 ch2, ch3, ch4;
|
||||
if (end - s < 4) {
|
||||
/* unexpected end of data: the caller will decide whether
|
||||
it's an error or not */
|
||||
if (end - s < 2)
|
||||
break;
|
||||
ch2 = (unsigned char)s[1];
|
||||
if (!IS_CONTINUATION_BYTE(ch2) ||
|
||||
(ch2 < 0x90 ? ch == 0xF0 : ch == 0xF4))
|
||||
/* for clarification see comments below */
|
||||
goto InvalidContinuation1;
|
||||
if (end - s < 3)
|
||||
break;
|
||||
ch3 = (unsigned char)s[2];
|
||||
if (!IS_CONTINUATION_BYTE(ch3))
|
||||
goto InvalidContinuation2;
|
||||
break;
|
||||
}
|
||||
ch2 = (unsigned char)s[1];
|
||||
ch3 = (unsigned char)s[2];
|
||||
ch4 = (unsigned char)s[3];
|
||||
if (!IS_CONTINUATION_BYTE(ch2)) {
|
||||
/* invalid continuation byte */
|
||||
goto InvalidContinuation1;
|
||||
}
|
||||
if (ch == 0xF0) {
|
||||
if (ch2 < 0x90)
|
||||
/* invalid sequence
|
||||
\xF0\x80\x80\x80-\xF0\x8F\xBF\xBF -- fake 0000-FFFF */
|
||||
goto InvalidContinuation1;
|
||||
} else if (ch == 0xF4 && ch2 >= 0x90) {
|
||||
/* invalid sequence
|
||||
\xF4\x90\x80\80- -- 110000- overflow */
|
||||
goto InvalidContinuation1;
|
||||
}
|
||||
if (!IS_CONTINUATION_BYTE(ch3)) {
|
||||
/* invalid continuation byte */
|
||||
goto InvalidContinuation2;
|
||||
}
|
||||
if (!IS_CONTINUATION_BYTE(ch4)) {
|
||||
/* invalid continuation byte */
|
||||
goto InvalidContinuation3;
|
||||
}
|
||||
ch = (ch << 18) + (ch2 << 12) + (ch3 << 6) + ch4 -
|
||||
((0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80);
|
||||
assert ((ch > 0xFFFF) && (ch <= 0x10FFFF));
|
||||
s += 4;
|
||||
if (STRINGLIB_MAX_CHAR <= 0xFFFF ||
|
||||
(STRINGLIB_MAX_CHAR < 0x10FFFF && ch > STRINGLIB_MAX_CHAR))
|
||||
/* Out-of-range */
|
||||
goto Return;
|
||||
*p++ = ch;
|
||||
continue;
|
||||
}
|
||||
goto InvalidStart;
|
||||
}
|
||||
ch = 0;
|
||||
Return:
|
||||
*inptr = s;
|
||||
*outpos = p - dest;
|
||||
return ch;
|
||||
InvalidStart:
|
||||
ch = 1;
|
||||
goto Return;
|
||||
InvalidContinuation1:
|
||||
ch = 2;
|
||||
goto Return;
|
||||
InvalidContinuation2:
|
||||
ch = 3;
|
||||
goto Return;
|
||||
InvalidContinuation3:
|
||||
ch = 4;
|
||||
goto Return;
|
||||
}
|
||||
|
||||
#undef ASCII_CHAR_MASK
|
||||
|
||||
|
||||
/* UTF-8 encoder specialized for a Unicode kind to avoid the slow
|
||||
PyUnicode_READ() macro. Delete some parts of the code depending on the kind:
|
||||
UCS-1 strings don't need to handle surrogates for example. */
|
||||
Py_LOCAL_INLINE(PyObject *)
|
||||
STRINGLIB(utf8_encoder)(PyObject *unicode,
|
||||
STRINGLIB_CHAR *data,
|
||||
Py_ssize_t size,
|
||||
const char *errors)
|
||||
{
|
||||
Py_ssize_t i; /* index into data of next input character */
|
||||
char *p; /* next free byte in output buffer */
|
||||
#if STRINGLIB_SIZEOF_CHAR > 1
|
||||
PyObject *error_handler_obj = NULL;
|
||||
PyObject *exc = NULL;
|
||||
PyObject *rep = NULL;
|
||||
_Py_error_handler error_handler = _Py_ERROR_UNKNOWN;
|
||||
#endif
|
||||
#if STRINGLIB_SIZEOF_CHAR == 1
|
||||
const Py_ssize_t max_char_size = 2;
|
||||
#elif STRINGLIB_SIZEOF_CHAR == 2
|
||||
const Py_ssize_t max_char_size = 3;
|
||||
#else /* STRINGLIB_SIZEOF_CHAR == 4 */
|
||||
const Py_ssize_t max_char_size = 4;
|
||||
#endif
|
||||
_PyBytesWriter writer;
|
||||
|
||||
assert(size >= 0);
|
||||
_PyBytesWriter_Init(&writer);
|
||||
|
||||
if (size > PY_SSIZE_T_MAX / max_char_size) {
|
||||
/* integer overflow */
|
||||
return PyErr_NoMemory();
|
||||
}
|
||||
|
||||
p = _PyBytesWriter_Alloc(&writer, size * max_char_size);
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < size;) {
|
||||
Py_UCS4 ch = data[i++];
|
||||
|
||||
if (ch < 0x80) {
|
||||
/* Encode ASCII */
|
||||
*p++ = (char) ch;
|
||||
|
||||
}
|
||||
else
|
||||
#if STRINGLIB_SIZEOF_CHAR > 1
|
||||
if (ch < 0x0800)
|
||||
#endif
|
||||
{
|
||||
/* Encode Latin-1 */
|
||||
*p++ = (char)(0xc0 | (ch >> 6));
|
||||
*p++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
#if STRINGLIB_SIZEOF_CHAR > 1
|
||||
else if (Py_UNICODE_IS_SURROGATE(ch)) {
|
||||
Py_ssize_t startpos, endpos, newpos;
|
||||
Py_ssize_t k;
|
||||
if (error_handler == _Py_ERROR_UNKNOWN) {
|
||||
error_handler = get_error_handler(errors);
|
||||
}
|
||||
|
||||
startpos = i-1;
|
||||
endpos = startpos+1;
|
||||
|
||||
while ((endpos < size) && Py_UNICODE_IS_SURROGATE(data[endpos]))
|
||||
endpos++;
|
||||
|
||||
/* Only overallocate the buffer if it's not the last write */
|
||||
writer.overallocate = (endpos < size);
|
||||
|
||||
switch (error_handler)
|
||||
{
|
||||
case _Py_ERROR_REPLACE:
|
||||
memset(p, '?', endpos - startpos);
|
||||
p += (endpos - startpos);
|
||||
/* fall through */
|
||||
case _Py_ERROR_IGNORE:
|
||||
i += (endpos - startpos - 1);
|
||||
break;
|
||||
|
||||
case _Py_ERROR_SURROGATEPASS:
|
||||
for (k=startpos; k<endpos; k++) {
|
||||
ch = data[k];
|
||||
*p++ = (char)(0xe0 | (ch >> 12));
|
||||
*p++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*p++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
i += (endpos - startpos - 1);
|
||||
break;
|
||||
|
||||
case _Py_ERROR_BACKSLASHREPLACE:
|
||||
/* subtract preallocated bytes */
|
||||
writer.min_size -= max_char_size * (endpos - startpos);
|
||||
p = backslashreplace(&writer, p,
|
||||
unicode, startpos, endpos);
|
||||
if (p == NULL)
|
||||
goto error;
|
||||
i += (endpos - startpos - 1);
|
||||
break;
|
||||
|
||||
case _Py_ERROR_XMLCHARREFREPLACE:
|
||||
/* subtract preallocated bytes */
|
||||
writer.min_size -= max_char_size * (endpos - startpos);
|
||||
p = xmlcharrefreplace(&writer, p,
|
||||
unicode, startpos, endpos);
|
||||
if (p == NULL)
|
||||
goto error;
|
||||
i += (endpos - startpos - 1);
|
||||
break;
|
||||
|
||||
case _Py_ERROR_SURROGATEESCAPE:
|
||||
for (k=startpos; k<endpos; k++) {
|
||||
ch = data[k];
|
||||
if (!(0xDC80 <= ch && ch <= 0xDCFF))
|
||||
break;
|
||||
*p++ = (char)(ch & 0xff);
|
||||
}
|
||||
if (k >= endpos) {
|
||||
i += (endpos - startpos - 1);
|
||||
break;
|
||||
}
|
||||
startpos = k;
|
||||
assert(startpos < endpos);
|
||||
/* fall through */
|
||||
default:
|
||||
rep = unicode_encode_call_errorhandler(
|
||||
errors, &error_handler_obj, "utf-8", "surrogates not allowed",
|
||||
unicode, &exc, startpos, endpos, &newpos);
|
||||
if (!rep)
|
||||
goto error;
|
||||
|
||||
/* subtract preallocated bytes */
|
||||
writer.min_size -= max_char_size * (newpos - startpos);
|
||||
|
||||
if (PyBytes_Check(rep)) {
|
||||
p = _PyBytesWriter_WriteBytes(&writer, p,
|
||||
PyBytes_AS_STRING(rep),
|
||||
PyBytes_GET_SIZE(rep));
|
||||
}
|
||||
else {
|
||||
/* rep is unicode */
|
||||
if (PyUnicode_READY(rep) < 0)
|
||||
goto error;
|
||||
|
||||
if (!PyUnicode_IS_ASCII(rep)) {
|
||||
raise_encode_exception(&exc, "utf-8", unicode,
|
||||
startpos, endpos,
|
||||
"surrogates not allowed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
p = _PyBytesWriter_WriteBytes(&writer, p,
|
||||
PyUnicode_DATA(rep),
|
||||
PyUnicode_GET_LENGTH(rep));
|
||||
}
|
||||
|
||||
if (p == NULL)
|
||||
goto error;
|
||||
Py_CLEAR(rep);
|
||||
|
||||
i = newpos;
|
||||
}
|
||||
|
||||
/* If overallocation was disabled, ensure that it was the last
|
||||
write. Otherwise, we missed an optimization */
|
||||
assert(writer.overallocate || i == size);
|
||||
}
|
||||
else
|
||||
#if STRINGLIB_SIZEOF_CHAR > 2
|
||||
if (ch < 0x10000)
|
||||
#endif
|
||||
{
|
||||
*p++ = (char)(0xe0 | (ch >> 12));
|
||||
*p++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*p++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
#if STRINGLIB_SIZEOF_CHAR > 2
|
||||
else /* ch >= 0x10000 */
|
||||
{
|
||||
assert(ch <= MAX_UNICODE);
|
||||
/* Encode UCS4 Unicode ordinals */
|
||||
*p++ = (char)(0xf0 | (ch >> 18));
|
||||
*p++ = (char)(0x80 | ((ch >> 12) & 0x3f));
|
||||
*p++ = (char)(0x80 | ((ch >> 6) & 0x3f));
|
||||
*p++ = (char)(0x80 | (ch & 0x3f));
|
||||
}
|
||||
#endif /* STRINGLIB_SIZEOF_CHAR > 2 */
|
||||
#endif /* STRINGLIB_SIZEOF_CHAR > 1 */
|
||||
}
|
||||
|
||||
#if STRINGLIB_SIZEOF_CHAR > 1
|
||||
Py_XDECREF(error_handler_obj);
|
||||
Py_XDECREF(exc);
|
||||
#endif
|
||||
return _PyBytesWriter_Finish(&writer, p);
|
||||
|
||||
#if STRINGLIB_SIZEOF_CHAR > 1
|
||||
error:
|
||||
Py_XDECREF(rep);
|
||||
Py_XDECREF(error_handler_obj);
|
||||
Py_XDECREF(exc);
|
||||
_PyBytesWriter_Dealloc(&writer);
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* The pattern for constructing UCS2-repeated masks. */
|
||||
#if SIZEOF_LONG == 8
|
||||
# define UCS2_REPEAT_MASK 0x0001000100010001ul
|
||||
#elif SIZEOF_LONG == 4
|
||||
# define UCS2_REPEAT_MASK 0x00010001ul
|
||||
#else
|
||||
# error C 'long' size should be either 4 or 8!
|
||||
#endif
|
||||
|
||||
/* The mask for fast checking. */
|
||||
#if STRINGLIB_SIZEOF_CHAR == 1
|
||||
/* The mask for fast checking of whether a C 'long' contains a
|
||||
non-ASCII or non-Latin1 UTF16-encoded characters. */
|
||||
# define FAST_CHAR_MASK (UCS2_REPEAT_MASK * (0xFFFFu & ~STRINGLIB_MAX_CHAR))
|
||||
#else
|
||||
/* The mask for fast checking of whether a C 'long' may contain
|
||||
UTF16-encoded surrogate characters. This is an efficient heuristic,
|
||||
assuming that non-surrogate characters with a code point >= 0x8000 are
|
||||
rare in most input.
|
||||
*/
|
||||
# define FAST_CHAR_MASK (UCS2_REPEAT_MASK * 0x8000u)
|
||||
#endif
|
||||
/* The mask for fast byte-swapping. */
|
||||
#define STRIPPED_MASK (UCS2_REPEAT_MASK * 0x00FFu)
|
||||
/* Swap bytes. */
|
||||
#define SWAB(value) ((((value) >> 8) & STRIPPED_MASK) | \
|
||||
(((value) & STRIPPED_MASK) << 8))
|
||||
|
||||
Py_LOCAL_INLINE(Py_UCS4)
|
||||
STRINGLIB(utf16_decode)(const unsigned char **inptr, const unsigned char *e,
|
||||
STRINGLIB_CHAR *dest, Py_ssize_t *outpos,
|
||||
int native_ordering)
|
||||
{
|
||||
Py_UCS4 ch;
|
||||
const unsigned char *aligned_end =
|
||||
(const unsigned char *) _Py_ALIGN_DOWN(e, SIZEOF_LONG);
|
||||
const unsigned char *q = *inptr;
|
||||
STRINGLIB_CHAR *p = dest + *outpos;
|
||||
/* Offsets from q for retrieving byte pairs in the right order. */
|
||||
#if PY_LITTLE_ENDIAN
|
||||
int ihi = !!native_ordering, ilo = !native_ordering;
|
||||
#else
|
||||
int ihi = !native_ordering, ilo = !!native_ordering;
|
||||
#endif
|
||||
--e;
|
||||
|
||||
while (q < e) {
|
||||
Py_UCS4 ch2;
|
||||
/* First check for possible aligned read of a C 'long'. Unaligned
|
||||
reads are more expensive, better to defer to another iteration. */
|
||||
if (_Py_IS_ALIGNED(q, SIZEOF_LONG)) {
|
||||
/* Fast path for runs of in-range non-surrogate chars. */
|
||||
const unsigned char *_q = q;
|
||||
while (_q < aligned_end) {
|
||||
unsigned long block = * (unsigned long *) _q;
|
||||
if (native_ordering) {
|
||||
/* Can use buffer directly */
|
||||
if (block & FAST_CHAR_MASK)
|
||||
break;
|
||||
}
|
||||
else {
|
||||
/* Need to byte-swap */
|
||||
if (block & SWAB(FAST_CHAR_MASK))
|
||||
break;
|
||||
#if STRINGLIB_SIZEOF_CHAR == 1
|
||||
block >>= 8;
|
||||
#else
|
||||
block = SWAB(block);
|
||||
#endif
|
||||
}
|
||||
#if PY_LITTLE_ENDIAN
|
||||
# if SIZEOF_LONG == 4
|
||||
p[0] = (STRINGLIB_CHAR)(block & 0xFFFFu);
|
||||
p[1] = (STRINGLIB_CHAR)(block >> 16);
|
||||
# elif SIZEOF_LONG == 8
|
||||
p[0] = (STRINGLIB_CHAR)(block & 0xFFFFu);
|
||||
p[1] = (STRINGLIB_CHAR)((block >> 16) & 0xFFFFu);
|
||||
p[2] = (STRINGLIB_CHAR)((block >> 32) & 0xFFFFu);
|
||||
p[3] = (STRINGLIB_CHAR)(block >> 48);
|
||||
# endif
|
||||
#else
|
||||
# if SIZEOF_LONG == 4
|
||||
p[0] = (STRINGLIB_CHAR)(block >> 16);
|
||||
p[1] = (STRINGLIB_CHAR)(block & 0xFFFFu);
|
||||
# elif SIZEOF_LONG == 8
|
||||
p[0] = (STRINGLIB_CHAR)(block >> 48);
|
||||
p[1] = (STRINGLIB_CHAR)((block >> 32) & 0xFFFFu);
|
||||
p[2] = (STRINGLIB_CHAR)((block >> 16) & 0xFFFFu);
|
||||
p[3] = (STRINGLIB_CHAR)(block & 0xFFFFu);
|
||||
# endif
|
||||
#endif
|
||||
_q += SIZEOF_LONG;
|
||||
p += SIZEOF_LONG / 2;
|
||||
}
|
||||
q = _q;
|
||||
if (q >= e)
|
||||
break;
|
||||
}
|
||||
|
||||
ch = (q[ihi] << 8) | q[ilo];
|
||||
q += 2;
|
||||
if (!Py_UNICODE_IS_SURROGATE(ch)) {
|
||||
#if STRINGLIB_SIZEOF_CHAR < 2
|
||||
if (ch > STRINGLIB_MAX_CHAR)
|
||||
/* Out-of-range */
|
||||
goto Return;
|
||||
#endif
|
||||
*p++ = (STRINGLIB_CHAR)ch;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* UTF-16 code pair: */
|
||||
if (q >= e)
|
||||
goto UnexpectedEnd;
|
||||
if (!Py_UNICODE_IS_HIGH_SURROGATE(ch))
|
||||
goto IllegalEncoding;
|
||||
ch2 = (q[ihi] << 8) | q[ilo];
|
||||
q += 2;
|
||||
if (!Py_UNICODE_IS_LOW_SURROGATE(ch2))
|
||||
goto IllegalSurrogate;
|
||||
ch = Py_UNICODE_JOIN_SURROGATES(ch, ch2);
|
||||
#if STRINGLIB_SIZEOF_CHAR < 4
|
||||
/* Out-of-range */
|
||||
goto Return;
|
||||
#else
|
||||
*p++ = (STRINGLIB_CHAR)ch;
|
||||
#endif
|
||||
}
|
||||
ch = 0;
|
||||
Return:
|
||||
*inptr = q;
|
||||
*outpos = p - dest;
|
||||
return ch;
|
||||
UnexpectedEnd:
|
||||
ch = 1;
|
||||
goto Return;
|
||||
IllegalEncoding:
|
||||
ch = 2;
|
||||
goto Return;
|
||||
IllegalSurrogate:
|
||||
ch = 3;
|
||||
goto Return;
|
||||
}
|
||||
#undef UCS2_REPEAT_MASK
|
||||
#undef FAST_CHAR_MASK
|
||||
#undef STRIPPED_MASK
|
||||
#undef SWAB
|
||||
|
||||
|
||||
#if STRINGLIB_MAX_CHAR >= 0x80
|
||||
Py_LOCAL_INLINE(Py_ssize_t)
|
||||
STRINGLIB(utf16_encode)(const STRINGLIB_CHAR *in,
|
||||
Py_ssize_t len,
|
||||
unsigned short **outptr,
|
||||
int native_ordering)
|
||||
{
|
||||
unsigned short *out = *outptr;
|
||||
const STRINGLIB_CHAR *end = in + len;
|
||||
#if STRINGLIB_SIZEOF_CHAR == 1
|
||||
if (native_ordering) {
|
||||
const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4);
|
||||
while (in < unrolled_end) {
|
||||
out[0] = in[0];
|
||||
out[1] = in[1];
|
||||
out[2] = in[2];
|
||||
out[3] = in[3];
|
||||
in += 4; out += 4;
|
||||
}
|
||||
while (in < end) {
|
||||
*out++ = *in++;
|
||||
}
|
||||
} else {
|
||||
# define SWAB2(CH) ((CH) << 8) /* high byte is zero */
|
||||
const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4);
|
||||
while (in < unrolled_end) {
|
||||
out[0] = SWAB2(in[0]);
|
||||
out[1] = SWAB2(in[1]);
|
||||
out[2] = SWAB2(in[2]);
|
||||
out[3] = SWAB2(in[3]);
|
||||
in += 4; out += 4;
|
||||
}
|
||||
while (in < end) {
|
||||
Py_UCS4 ch = *in++;
|
||||
*out++ = SWAB2((Py_UCS2)ch);
|
||||
}
|
||||
#undef SWAB2
|
||||
}
|
||||
*outptr = out;
|
||||
return len;
|
||||
#else
|
||||
if (native_ordering) {
|
||||
#if STRINGLIB_MAX_CHAR < 0x10000
|
||||
const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4);
|
||||
while (in < unrolled_end) {
|
||||
/* check if any character is a surrogate character */
|
||||
if (((in[0] ^ 0xd800) &
|
||||
(in[1] ^ 0xd800) &
|
||||
(in[2] ^ 0xd800) &
|
||||
(in[3] ^ 0xd800) & 0xf800) == 0)
|
||||
break;
|
||||
out[0] = in[0];
|
||||
out[1] = in[1];
|
||||
out[2] = in[2];
|
||||
out[3] = in[3];
|
||||
in += 4; out += 4;
|
||||
}
|
||||
#endif
|
||||
while (in < end) {
|
||||
Py_UCS4 ch;
|
||||
ch = *in++;
|
||||
if (ch < 0xd800)
|
||||
*out++ = ch;
|
||||
else if (ch < 0xe000)
|
||||
/* reject surrogate characters (U+D800-U+DFFF) */
|
||||
goto fail;
|
||||
#if STRINGLIB_MAX_CHAR >= 0x10000
|
||||
else if (ch >= 0x10000) {
|
||||
out[0] = Py_UNICODE_HIGH_SURROGATE(ch);
|
||||
out[1] = Py_UNICODE_LOW_SURROGATE(ch);
|
||||
out += 2;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
*out++ = ch;
|
||||
}
|
||||
} else {
|
||||
#define SWAB2(CH) (((CH) << 8) | ((CH) >> 8))
|
||||
#if STRINGLIB_MAX_CHAR < 0x10000
|
||||
const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4);
|
||||
while (in < unrolled_end) {
|
||||
/* check if any character is a surrogate character */
|
||||
if (((in[0] ^ 0xd800) &
|
||||
(in[1] ^ 0xd800) &
|
||||
(in[2] ^ 0xd800) &
|
||||
(in[3] ^ 0xd800) & 0xf800) == 0)
|
||||
break;
|
||||
out[0] = SWAB2(in[0]);
|
||||
out[1] = SWAB2(in[1]);
|
||||
out[2] = SWAB2(in[2]);
|
||||
out[3] = SWAB2(in[3]);
|
||||
in += 4; out += 4;
|
||||
}
|
||||
#endif
|
||||
while (in < end) {
|
||||
Py_UCS4 ch = *in++;
|
||||
if (ch < 0xd800)
|
||||
*out++ = SWAB2((Py_UCS2)ch);
|
||||
else if (ch < 0xe000)
|
||||
/* reject surrogate characters (U+D800-U+DFFF) */
|
||||
goto fail;
|
||||
#if STRINGLIB_MAX_CHAR >= 0x10000
|
||||
else if (ch >= 0x10000) {
|
||||
Py_UCS2 ch1 = Py_UNICODE_HIGH_SURROGATE(ch);
|
||||
Py_UCS2 ch2 = Py_UNICODE_LOW_SURROGATE(ch);
|
||||
out[0] = SWAB2(ch1);
|
||||
out[1] = SWAB2(ch2);
|
||||
out += 2;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
*out++ = SWAB2((Py_UCS2)ch);
|
||||
}
|
||||
#undef SWAB2
|
||||
}
|
||||
*outptr = out;
|
||||
return len;
|
||||
fail:
|
||||
*outptr = out;
|
||||
return len - (end - in + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if STRINGLIB_SIZEOF_CHAR == 1
|
||||
# define SWAB4(CH, tmp) ((CH) << 24) /* high bytes are zero */
|
||||
#elif STRINGLIB_SIZEOF_CHAR == 2
|
||||
# define SWAB4(CH, tmp) (tmp = (CH), \
|
||||
((tmp & 0x00FFu) << 24) + ((tmp & 0xFF00u) << 8))
|
||||
/* high bytes are zero */
|
||||
#else
|
||||
# define SWAB4(CH, tmp) (tmp = (CH), \
|
||||
tmp = ((tmp & 0x00FF00FFu) << 8) + ((tmp >> 8) & 0x00FF00FFu), \
|
||||
((tmp & 0x0000FFFFu) << 16) + ((tmp >> 16) & 0x0000FFFFu))
|
||||
#endif
|
||||
Py_LOCAL_INLINE(Py_ssize_t)
|
||||
STRINGLIB(utf32_encode)(const STRINGLIB_CHAR *in,
|
||||
Py_ssize_t len,
|
||||
PY_UINT32_T **outptr,
|
||||
int native_ordering)
|
||||
{
|
||||
PY_UINT32_T *out = *outptr;
|
||||
const STRINGLIB_CHAR *end = in + len;
|
||||
if (native_ordering) {
|
||||
const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4);
|
||||
while (in < unrolled_end) {
|
||||
#if STRINGLIB_SIZEOF_CHAR > 1
|
||||
/* check if any character is a surrogate character */
|
||||
if (((in[0] ^ 0xd800) &
|
||||
(in[1] ^ 0xd800) &
|
||||
(in[2] ^ 0xd800) &
|
||||
(in[3] ^ 0xd800) & 0xf800) == 0)
|
||||
break;
|
||||
#endif
|
||||
out[0] = in[0];
|
||||
out[1] = in[1];
|
||||
out[2] = in[2];
|
||||
out[3] = in[3];
|
||||
in += 4; out += 4;
|
||||
}
|
||||
while (in < end) {
|
||||
Py_UCS4 ch;
|
||||
ch = *in++;
|
||||
#if STRINGLIB_SIZEOF_CHAR > 1
|
||||
if (Py_UNICODE_IS_SURROGATE(ch)) {
|
||||
/* reject surrogate characters (U+D800-U+DFFF) */
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
*out++ = ch;
|
||||
}
|
||||
} else {
|
||||
const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4);
|
||||
while (in < unrolled_end) {
|
||||
#if STRINGLIB_SIZEOF_CHAR > 1
|
||||
Py_UCS4 ch1, ch2, ch3, ch4;
|
||||
/* check if any character is a surrogate character */
|
||||
if (((in[0] ^ 0xd800) &
|
||||
(in[1] ^ 0xd800) &
|
||||
(in[2] ^ 0xd800) &
|
||||
(in[3] ^ 0xd800) & 0xf800) == 0)
|
||||
break;
|
||||
#endif
|
||||
out[0] = SWAB4(in[0], ch1);
|
||||
out[1] = SWAB4(in[1], ch2);
|
||||
out[2] = SWAB4(in[2], ch3);
|
||||
out[3] = SWAB4(in[3], ch4);
|
||||
in += 4; out += 4;
|
||||
}
|
||||
while (in < end) {
|
||||
Py_UCS4 ch = *in++;
|
||||
#if STRINGLIB_SIZEOF_CHAR > 1
|
||||
if (Py_UNICODE_IS_SURROGATE(ch)) {
|
||||
/* reject surrogate characters (U+D800-U+DFFF) */
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
*out++ = SWAB4(ch, ch);
|
||||
}
|
||||
}
|
||||
*outptr = out;
|
||||
return len;
|
||||
#if STRINGLIB_SIZEOF_CHAR > 1
|
||||
fail:
|
||||
*outptr = out;
|
||||
return len - (end - in + 1);
|
||||
#endif
|
||||
}
|
||||
#undef SWAB4
|
||||
|
||||
#endif
|
27
third_party/python/Objects/stringlib/count.h
vendored
Normal file
27
third_party/python/Objects/stringlib/count.h
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* stringlib: count implementation */
|
||||
|
||||
#ifndef STRINGLIB_FASTSEARCH_H
|
||||
#error must include "stringlib/fastsearch.h" before including this module
|
||||
#endif
|
||||
|
||||
Py_LOCAL_INLINE(Py_ssize_t)
|
||||
STRINGLIB(count)(const STRINGLIB_CHAR* str, Py_ssize_t str_len,
|
||||
const STRINGLIB_CHAR* sub, Py_ssize_t sub_len,
|
||||
Py_ssize_t maxcount)
|
||||
{
|
||||
Py_ssize_t count;
|
||||
|
||||
if (str_len < 0)
|
||||
return 0; /* start > len(str) */
|
||||
if (sub_len == 0)
|
||||
return (str_len < maxcount) ? str_len + 1 : maxcount;
|
||||
|
||||
count = FASTSEARCH(str, str_len, sub, sub_len, maxcount, FAST_COUNT);
|
||||
|
||||
if (count < 0)
|
||||
return 0; /* no match */
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
110
third_party/python/Objects/stringlib/ctype.h
vendored
Normal file
110
third_party/python/Objects/stringlib/ctype.h
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
#if STRINGLIB_IS_UNICODE
|
||||
# error "ctype.h only compatible with byte-wise strings"
|
||||
#endif
|
||||
|
||||
#include "bytes_methods.h"
|
||||
|
||||
static PyObject*
|
||||
stringlib_isspace(PyObject *self)
|
||||
{
|
||||
return _Py_bytes_isspace(STRINGLIB_STR(self), STRINGLIB_LEN(self));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
stringlib_isalpha(PyObject *self)
|
||||
{
|
||||
return _Py_bytes_isalpha(STRINGLIB_STR(self), STRINGLIB_LEN(self));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
stringlib_isalnum(PyObject *self)
|
||||
{
|
||||
return _Py_bytes_isalnum(STRINGLIB_STR(self), STRINGLIB_LEN(self));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
stringlib_isdigit(PyObject *self)
|
||||
{
|
||||
return _Py_bytes_isdigit(STRINGLIB_STR(self), STRINGLIB_LEN(self));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
stringlib_islower(PyObject *self)
|
||||
{
|
||||
return _Py_bytes_islower(STRINGLIB_STR(self), STRINGLIB_LEN(self));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
stringlib_isupper(PyObject *self)
|
||||
{
|
||||
return _Py_bytes_isupper(STRINGLIB_STR(self), STRINGLIB_LEN(self));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
stringlib_istitle(PyObject *self)
|
||||
{
|
||||
return _Py_bytes_istitle(STRINGLIB_STR(self), STRINGLIB_LEN(self));
|
||||
}
|
||||
|
||||
|
||||
/* functions that return a new object partially translated by ctype funcs: */
|
||||
|
||||
static PyObject*
|
||||
stringlib_lower(PyObject *self)
|
||||
{
|
||||
PyObject* newobj;
|
||||
newobj = STRINGLIB_NEW(NULL, STRINGLIB_LEN(self));
|
||||
if (!newobj)
|
||||
return NULL;
|
||||
_Py_bytes_lower(STRINGLIB_STR(newobj), STRINGLIB_STR(self),
|
||||
STRINGLIB_LEN(self));
|
||||
return newobj;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
stringlib_upper(PyObject *self)
|
||||
{
|
||||
PyObject* newobj;
|
||||
newobj = STRINGLIB_NEW(NULL, STRINGLIB_LEN(self));
|
||||
if (!newobj)
|
||||
return NULL;
|
||||
_Py_bytes_upper(STRINGLIB_STR(newobj), STRINGLIB_STR(self),
|
||||
STRINGLIB_LEN(self));
|
||||
return newobj;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
stringlib_title(PyObject *self)
|
||||
{
|
||||
PyObject* newobj;
|
||||
newobj = STRINGLIB_NEW(NULL, STRINGLIB_LEN(self));
|
||||
if (!newobj)
|
||||
return NULL;
|
||||
_Py_bytes_title(STRINGLIB_STR(newobj), STRINGLIB_STR(self),
|
||||
STRINGLIB_LEN(self));
|
||||
return newobj;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
stringlib_capitalize(PyObject *self)
|
||||
{
|
||||
PyObject* newobj;
|
||||
newobj = STRINGLIB_NEW(NULL, STRINGLIB_LEN(self));
|
||||
if (!newobj)
|
||||
return NULL;
|
||||
_Py_bytes_capitalize(STRINGLIB_STR(newobj), STRINGLIB_STR(self),
|
||||
STRINGLIB_LEN(self));
|
||||
return newobj;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
stringlib_swapcase(PyObject *self)
|
||||
{
|
||||
PyObject* newobj;
|
||||
newobj = STRINGLIB_NEW(NULL, STRINGLIB_LEN(self));
|
||||
if (!newobj)
|
||||
return NULL;
|
||||
_Py_bytes_swapcase(STRINGLIB_STR(newobj), STRINGLIB_STR(self),
|
||||
STRINGLIB_LEN(self));
|
||||
return newobj;
|
||||
}
|
25
third_party/python/Objects/stringlib/eq.h
vendored
Normal file
25
third_party/python/Objects/stringlib/eq.h
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
/* Fast unicode equal function optimized for dictobject.c and setobject.c */
|
||||
|
||||
/* Return 1 if two unicode objects are equal, 0 if not.
|
||||
* unicode_eq() is called when the hash of two unicode objects is equal.
|
||||
*/
|
||||
Py_LOCAL_INLINE(int)
|
||||
unicode_eq(PyObject *aa, PyObject *bb)
|
||||
{
|
||||
PyUnicodeObject *a = (PyUnicodeObject *)aa;
|
||||
PyUnicodeObject *b = (PyUnicodeObject *)bb;
|
||||
|
||||
if (PyUnicode_READY(a) == -1 || PyUnicode_READY(b) == -1) {
|
||||
assert(0 && "unicode_eq ready fail");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (PyUnicode_GET_LENGTH(a) != PyUnicode_GET_LENGTH(b))
|
||||
return 0;
|
||||
if (PyUnicode_GET_LENGTH(a) == 0)
|
||||
return 1;
|
||||
if (PyUnicode_KIND(a) != PyUnicode_KIND(b))
|
||||
return 0;
|
||||
return memcmp(PyUnicode_1BYTE_DATA(a), PyUnicode_1BYTE_DATA(b),
|
||||
PyUnicode_GET_LENGTH(a) * PyUnicode_KIND(a)) == 0;
|
||||
}
|
250
third_party/python/Objects/stringlib/fastsearch.h
vendored
Normal file
250
third_party/python/Objects/stringlib/fastsearch.h
vendored
Normal file
|
@ -0,0 +1,250 @@
|
|||
/* stringlib: fastsearch implementation */
|
||||
|
||||
#define STRINGLIB_FASTSEARCH_H
|
||||
|
||||
/* fast search/count implementation, based on a mix between boyer-
|
||||
moore and horspool, with a few more bells and whistles on the top.
|
||||
for some more background, see: http://effbot.org/zone/stringlib.htm */
|
||||
|
||||
/* note: fastsearch may access s[n], which isn't a problem when using
|
||||
Python's ordinary string types, but may cause problems if you're
|
||||
using this code in other contexts. also, the count mode returns -1
|
||||
if there cannot possible be a match in the target string, and 0 if
|
||||
it has actually checked for matches, but didn't find any. callers
|
||||
beware! */
|
||||
|
||||
#define FAST_COUNT 0
|
||||
#define FAST_SEARCH 1
|
||||
#define FAST_RSEARCH 2
|
||||
|
||||
#if LONG_BIT >= 128
|
||||
#define STRINGLIB_BLOOM_WIDTH 128
|
||||
#elif LONG_BIT >= 64
|
||||
#define STRINGLIB_BLOOM_WIDTH 64
|
||||
#elif LONG_BIT >= 32
|
||||
#define STRINGLIB_BLOOM_WIDTH 32
|
||||
#else
|
||||
#error "LONG_BIT is smaller than 32"
|
||||
#endif
|
||||
|
||||
#define STRINGLIB_BLOOM_ADD(mask, ch) \
|
||||
((mask |= (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1)))))
|
||||
#define STRINGLIB_BLOOM(mask, ch) \
|
||||
((mask & (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1)))))
|
||||
|
||||
Py_LOCAL_INLINE(Py_ssize_t)
|
||||
STRINGLIB(find_char)(const STRINGLIB_CHAR* s, Py_ssize_t n, STRINGLIB_CHAR ch)
|
||||
{
|
||||
const STRINGLIB_CHAR *p, *e;
|
||||
|
||||
p = s;
|
||||
e = s + n;
|
||||
if (n > 10) {
|
||||
#if STRINGLIB_SIZEOF_CHAR == 1
|
||||
p = memchr(s, ch, n);
|
||||
if (p != NULL)
|
||||
return (p - s);
|
||||
return -1;
|
||||
#else
|
||||
/* use memchr if we can choose a needle without two many likely
|
||||
false positives */
|
||||
unsigned char needle = ch & 0xff;
|
||||
/* If looking for a multiple of 256, we'd have too
|
||||
many false positives looking for the '\0' byte in UCS2
|
||||
and UCS4 representations. */
|
||||
if (needle != 0) {
|
||||
while (p < e) {
|
||||
void *candidate = memchr(p, needle,
|
||||
(e - p) * sizeof(STRINGLIB_CHAR));
|
||||
if (candidate == NULL)
|
||||
return -1;
|
||||
p = (const STRINGLIB_CHAR *)
|
||||
_Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
|
||||
if (*p == ch)
|
||||
return (p - s);
|
||||
/* False positive */
|
||||
p++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
while (p < e) {
|
||||
if (*p == ch)
|
||||
return (p - s);
|
||||
p++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Py_LOCAL_INLINE(Py_ssize_t)
|
||||
STRINGLIB(rfind_char)(const STRINGLIB_CHAR* s, Py_ssize_t n, STRINGLIB_CHAR ch)
|
||||
{
|
||||
const STRINGLIB_CHAR *p;
|
||||
#ifdef HAVE_MEMRCHR
|
||||
/* memrchr() is a GNU extension, available since glibc 2.1.91.
|
||||
it doesn't seem as optimized as memchr(), but is still quite
|
||||
faster than our hand-written loop below */
|
||||
|
||||
if (n > 10) {
|
||||
#if STRINGLIB_SIZEOF_CHAR == 1
|
||||
p = memrchr(s, ch, n);
|
||||
if (p != NULL)
|
||||
return (p - s);
|
||||
return -1;
|
||||
#else
|
||||
/* use memrchr if we can choose a needle without two many likely
|
||||
false positives */
|
||||
unsigned char needle = ch & 0xff;
|
||||
/* If looking for a multiple of 256, we'd have too
|
||||
many false positives looking for the '\0' byte in UCS2
|
||||
and UCS4 representations. */
|
||||
if (needle != 0) {
|
||||
while (n > 0) {
|
||||
void *candidate = memrchr(s, needle,
|
||||
n * sizeof(STRINGLIB_CHAR));
|
||||
if (candidate == NULL)
|
||||
return -1;
|
||||
p = (const STRINGLIB_CHAR *)
|
||||
_Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
|
||||
n = p - s;
|
||||
if (*p == ch)
|
||||
return n;
|
||||
/* False positive */
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* HAVE_MEMRCHR */
|
||||
p = s + n;
|
||||
while (p > s) {
|
||||
p--;
|
||||
if (*p == ch)
|
||||
return (p - s);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Py_LOCAL_INLINE(Py_ssize_t)
|
||||
FASTSEARCH(const STRINGLIB_CHAR* s, Py_ssize_t n,
|
||||
const STRINGLIB_CHAR* p, Py_ssize_t m,
|
||||
Py_ssize_t maxcount, int mode)
|
||||
{
|
||||
unsigned long mask;
|
||||
Py_ssize_t skip, count = 0;
|
||||
Py_ssize_t i, j, mlast, w;
|
||||
|
||||
w = n - m;
|
||||
|
||||
if (w < 0 || (mode == FAST_COUNT && maxcount == 0))
|
||||
return -1;
|
||||
|
||||
/* look for special cases */
|
||||
if (m <= 1) {
|
||||
if (m <= 0)
|
||||
return -1;
|
||||
/* use special case for 1-character strings */
|
||||
if (mode == FAST_SEARCH)
|
||||
return STRINGLIB(find_char)(s, n, p[0]);
|
||||
else if (mode == FAST_RSEARCH)
|
||||
return STRINGLIB(rfind_char)(s, n, p[0]);
|
||||
else { /* FAST_COUNT */
|
||||
for (i = 0; i < n; i++)
|
||||
if (s[i] == p[0]) {
|
||||
count++;
|
||||
if (count == maxcount)
|
||||
return maxcount;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
mlast = m - 1;
|
||||
skip = mlast - 1;
|
||||
mask = 0;
|
||||
|
||||
if (mode != FAST_RSEARCH) {
|
||||
const STRINGLIB_CHAR *ss = s + m - 1;
|
||||
const STRINGLIB_CHAR *pp = p + m - 1;
|
||||
|
||||
/* create compressed boyer-moore delta 1 table */
|
||||
|
||||
/* process pattern[:-1] */
|
||||
for (i = 0; i < mlast; i++) {
|
||||
STRINGLIB_BLOOM_ADD(mask, p[i]);
|
||||
if (p[i] == p[mlast])
|
||||
skip = mlast - i - 1;
|
||||
}
|
||||
/* process pattern[-1] outside the loop */
|
||||
STRINGLIB_BLOOM_ADD(mask, p[mlast]);
|
||||
|
||||
for (i = 0; i <= w; i++) {
|
||||
/* note: using mlast in the skip path slows things down on x86 */
|
||||
if (ss[i] == pp[0]) {
|
||||
/* candidate match */
|
||||
for (j = 0; j < mlast; j++)
|
||||
if (s[i+j] != p[j])
|
||||
break;
|
||||
if (j == mlast) {
|
||||
/* got a match! */
|
||||
if (mode != FAST_COUNT)
|
||||
return i;
|
||||
count++;
|
||||
if (count == maxcount)
|
||||
return maxcount;
|
||||
i = i + mlast;
|
||||
continue;
|
||||
}
|
||||
/* miss: check if next character is part of pattern */
|
||||
if (!STRINGLIB_BLOOM(mask, ss[i+1]))
|
||||
i = i + m;
|
||||
else
|
||||
i = i + skip;
|
||||
} else {
|
||||
/* skip: check if next character is part of pattern */
|
||||
if (!STRINGLIB_BLOOM(mask, ss[i+1]))
|
||||
i = i + m;
|
||||
}
|
||||
}
|
||||
} else { /* FAST_RSEARCH */
|
||||
|
||||
/* create compressed boyer-moore delta 1 table */
|
||||
|
||||
/* process pattern[0] outside the loop */
|
||||
STRINGLIB_BLOOM_ADD(mask, p[0]);
|
||||
/* process pattern[:0:-1] */
|
||||
for (i = mlast; i > 0; i--) {
|
||||
STRINGLIB_BLOOM_ADD(mask, p[i]);
|
||||
if (p[i] == p[0])
|
||||
skip = i - 1;
|
||||
}
|
||||
|
||||
for (i = w; i >= 0; i--) {
|
||||
if (s[i] == p[0]) {
|
||||
/* candidate match */
|
||||
for (j = mlast; j > 0; j--)
|
||||
if (s[i+j] != p[j])
|
||||
break;
|
||||
if (j == 0)
|
||||
/* got a match! */
|
||||
return i;
|
||||
/* miss: check if previous character is part of pattern */
|
||||
if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1]))
|
||||
i = i - m;
|
||||
else
|
||||
i = i - skip;
|
||||
} else {
|
||||
/* skip: check if previous character is part of pattern */
|
||||
if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1]))
|
||||
i = i - m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mode != FAST_COUNT)
|
||||
return -1;
|
||||
return count;
|
||||
}
|
||||
|
119
third_party/python/Objects/stringlib/find.h
vendored
Normal file
119
third_party/python/Objects/stringlib/find.h
vendored
Normal file
|
@ -0,0 +1,119 @@
|
|||
/* stringlib: find/index implementation */
|
||||
|
||||
#ifndef STRINGLIB_FASTSEARCH_H
|
||||
#error must include "stringlib/fastsearch.h" before including this module
|
||||
#endif
|
||||
|
||||
Py_LOCAL_INLINE(Py_ssize_t)
|
||||
STRINGLIB(find)(const STRINGLIB_CHAR* str, Py_ssize_t str_len,
|
||||
const STRINGLIB_CHAR* sub, Py_ssize_t sub_len,
|
||||
Py_ssize_t offset)
|
||||
{
|
||||
Py_ssize_t pos;
|
||||
|
||||
assert(str_len >= 0);
|
||||
if (sub_len == 0)
|
||||
return offset;
|
||||
|
||||
pos = FASTSEARCH(str, str_len, sub, sub_len, -1, FAST_SEARCH);
|
||||
|
||||
if (pos >= 0)
|
||||
pos += offset;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
Py_LOCAL_INLINE(Py_ssize_t)
|
||||
STRINGLIB(rfind)(const STRINGLIB_CHAR* str, Py_ssize_t str_len,
|
||||
const STRINGLIB_CHAR* sub, Py_ssize_t sub_len,
|
||||
Py_ssize_t offset)
|
||||
{
|
||||
Py_ssize_t pos;
|
||||
|
||||
assert(str_len >= 0);
|
||||
if (sub_len == 0)
|
||||
return str_len + offset;
|
||||
|
||||
pos = FASTSEARCH(str, str_len, sub, sub_len, -1, FAST_RSEARCH);
|
||||
|
||||
if (pos >= 0)
|
||||
pos += offset;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
Py_LOCAL_INLINE(Py_ssize_t)
|
||||
STRINGLIB(find_slice)(const STRINGLIB_CHAR* str, Py_ssize_t str_len,
|
||||
const STRINGLIB_CHAR* sub, Py_ssize_t sub_len,
|
||||
Py_ssize_t start, Py_ssize_t end)
|
||||
{
|
||||
return STRINGLIB(find)(str + start, end - start, sub, sub_len, start);
|
||||
}
|
||||
|
||||
Py_LOCAL_INLINE(Py_ssize_t)
|
||||
STRINGLIB(rfind_slice)(const STRINGLIB_CHAR* str, Py_ssize_t str_len,
|
||||
const STRINGLIB_CHAR* sub, Py_ssize_t sub_len,
|
||||
Py_ssize_t start, Py_ssize_t end)
|
||||
{
|
||||
return STRINGLIB(rfind)(str + start, end - start, sub, sub_len, start);
|
||||
}
|
||||
|
||||
#ifdef STRINGLIB_WANT_CONTAINS_OBJ
|
||||
|
||||
Py_LOCAL_INLINE(int)
|
||||
STRINGLIB(contains_obj)(PyObject* str, PyObject* sub)
|
||||
{
|
||||
return STRINGLIB(find)(
|
||||
STRINGLIB_STR(str), STRINGLIB_LEN(str),
|
||||
STRINGLIB_STR(sub), STRINGLIB_LEN(sub), 0
|
||||
) != -1;
|
||||
}
|
||||
|
||||
#endif /* STRINGLIB_WANT_CONTAINS_OBJ */
|
||||
|
||||
/*
|
||||
This function is a helper for the "find" family (find, rfind, index,
|
||||
rindex) and for count, startswith and endswith, because they all have
|
||||
the same behaviour for the arguments.
|
||||
|
||||
It does not touch the variables received until it knows everything
|
||||
is ok.
|
||||
*/
|
||||
|
||||
#define FORMAT_BUFFER_SIZE 50
|
||||
|
||||
Py_LOCAL_INLINE(int)
|
||||
STRINGLIB(parse_args_finds)(const char * function_name, PyObject *args,
|
||||
PyObject **subobj,
|
||||
Py_ssize_t *start, Py_ssize_t *end)
|
||||
{
|
||||
PyObject *tmp_subobj;
|
||||
Py_ssize_t tmp_start = 0;
|
||||
Py_ssize_t tmp_end = PY_SSIZE_T_MAX;
|
||||
PyObject *obj_start=Py_None, *obj_end=Py_None;
|
||||
char format[FORMAT_BUFFER_SIZE] = "O|OO:";
|
||||
size_t len = strlen(format);
|
||||
|
||||
strncpy(format + len, function_name, FORMAT_BUFFER_SIZE - len - 1);
|
||||
format[FORMAT_BUFFER_SIZE - 1] = '\0';
|
||||
|
||||
if (!PyArg_ParseTuple(args, format, &tmp_subobj, &obj_start, &obj_end))
|
||||
return 0;
|
||||
|
||||
/* To support None in "start" and "end" arguments, meaning
|
||||
the same as if they were not passed.
|
||||
*/
|
||||
if (obj_start != Py_None)
|
||||
if (!_PyEval_SliceIndex(obj_start, &tmp_start))
|
||||
return 0;
|
||||
if (obj_end != Py_None)
|
||||
if (!_PyEval_SliceIndex(obj_end, &tmp_end))
|
||||
return 0;
|
||||
|
||||
*start = tmp_start;
|
||||
*end = tmp_end;
|
||||
*subobj = tmp_subobj;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#undef FORMAT_BUFFER_SIZE
|
134
third_party/python/Objects/stringlib/find_max_char.h
vendored
Normal file
134
third_party/python/Objects/stringlib/find_max_char.h
vendored
Normal file
|
@ -0,0 +1,134 @@
|
|||
/* Finding the optimal width of unicode characters in a buffer */
|
||||
|
||||
#if !STRINGLIB_IS_UNICODE
|
||||
# error "find_max_char.h is specific to Unicode"
|
||||
#endif
|
||||
|
||||
/* Mask to quickly check whether a C 'long' contains a
|
||||
non-ASCII, UTF8-encoded char. */
|
||||
#if (SIZEOF_LONG == 8)
|
||||
# define UCS1_ASCII_CHAR_MASK 0x8080808080808080UL
|
||||
#elif (SIZEOF_LONG == 4)
|
||||
# define UCS1_ASCII_CHAR_MASK 0x80808080UL
|
||||
#else
|
||||
# error C 'long' size should be either 4 or 8!
|
||||
#endif
|
||||
|
||||
#if STRINGLIB_SIZEOF_CHAR == 1
|
||||
|
||||
Py_LOCAL_INLINE(Py_UCS4)
|
||||
STRINGLIB(find_max_char)(const STRINGLIB_CHAR *begin, const STRINGLIB_CHAR *end)
|
||||
{
|
||||
const unsigned char *p = (const unsigned char *) begin;
|
||||
const unsigned char *aligned_end =
|
||||
(const unsigned char *) _Py_ALIGN_DOWN(end, SIZEOF_LONG);
|
||||
|
||||
while (p < end) {
|
||||
if (_Py_IS_ALIGNED(p, SIZEOF_LONG)) {
|
||||
/* Help register allocation */
|
||||
const unsigned char *_p = p;
|
||||
while (_p < aligned_end) {
|
||||
unsigned long value = *(unsigned long *) _p;
|
||||
if (value & UCS1_ASCII_CHAR_MASK)
|
||||
return 255;
|
||||
_p += SIZEOF_LONG;
|
||||
}
|
||||
p = _p;
|
||||
if (p == end)
|
||||
break;
|
||||
}
|
||||
if (*p++ & 0x80)
|
||||
return 255;
|
||||
}
|
||||
return 127;
|
||||
}
|
||||
|
||||
#undef ASCII_CHAR_MASK
|
||||
|
||||
#else /* STRINGLIB_SIZEOF_CHAR == 1 */
|
||||
|
||||
#define MASK_ASCII 0xFFFFFF80
|
||||
#define MASK_UCS1 0xFFFFFF00
|
||||
#define MASK_UCS2 0xFFFF0000
|
||||
|
||||
#define MAX_CHAR_ASCII 0x7f
|
||||
#define MAX_CHAR_UCS1 0xff
|
||||
#define MAX_CHAR_UCS2 0xffff
|
||||
#define MAX_CHAR_UCS4 0x10ffff
|
||||
|
||||
Py_LOCAL_INLINE(Py_UCS4)
|
||||
STRINGLIB(find_max_char)(const STRINGLIB_CHAR *begin, const STRINGLIB_CHAR *end)
|
||||
{
|
||||
#if STRINGLIB_SIZEOF_CHAR == 2
|
||||
const Py_UCS4 mask_limit = MASK_UCS1;
|
||||
const Py_UCS4 max_char_limit = MAX_CHAR_UCS2;
|
||||
#elif STRINGLIB_SIZEOF_CHAR == 4
|
||||
const Py_UCS4 mask_limit = MASK_UCS2;
|
||||
const Py_UCS4 max_char_limit = MAX_CHAR_UCS4;
|
||||
#else
|
||||
#error Invalid STRINGLIB_SIZEOF_CHAR (must be 1, 2 or 4)
|
||||
#endif
|
||||
Py_UCS4 mask;
|
||||
Py_ssize_t n = end - begin;
|
||||
const STRINGLIB_CHAR *p = begin;
|
||||
const STRINGLIB_CHAR *unrolled_end = begin + _Py_SIZE_ROUND_DOWN(n, 4);
|
||||
Py_UCS4 max_char;
|
||||
|
||||
max_char = MAX_CHAR_ASCII;
|
||||
mask = MASK_ASCII;
|
||||
while (p < unrolled_end) {
|
||||
STRINGLIB_CHAR bits = p[0] | p[1] | p[2] | p[3];
|
||||
if (bits & mask) {
|
||||
if (mask == mask_limit) {
|
||||
/* Limit reached */
|
||||
return max_char_limit;
|
||||
}
|
||||
if (mask == MASK_ASCII) {
|
||||
max_char = MAX_CHAR_UCS1;
|
||||
mask = MASK_UCS1;
|
||||
}
|
||||
else {
|
||||
/* mask can't be MASK_UCS2 because of mask_limit above */
|
||||
assert(mask == MASK_UCS1);
|
||||
max_char = MAX_CHAR_UCS2;
|
||||
mask = MASK_UCS2;
|
||||
}
|
||||
/* We check the new mask on the same chars in the next iteration */
|
||||
continue;
|
||||
}
|
||||
p += 4;
|
||||
}
|
||||
while (p < end) {
|
||||
if (p[0] & mask) {
|
||||
if (mask == mask_limit) {
|
||||
/* Limit reached */
|
||||
return max_char_limit;
|
||||
}
|
||||
if (mask == MASK_ASCII) {
|
||||
max_char = MAX_CHAR_UCS1;
|
||||
mask = MASK_UCS1;
|
||||
}
|
||||
else {
|
||||
/* mask can't be MASK_UCS2 because of mask_limit above */
|
||||
assert(mask == MASK_UCS1);
|
||||
max_char = MAX_CHAR_UCS2;
|
||||
mask = MASK_UCS2;
|
||||
}
|
||||
/* We check the new mask on the same chars in the next iteration */
|
||||
continue;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return max_char;
|
||||
}
|
||||
|
||||
#undef MASK_ASCII
|
||||
#undef MASK_UCS1
|
||||
#undef MASK_UCS2
|
||||
#undef MAX_CHAR_ASCII
|
||||
#undef MAX_CHAR_UCS1
|
||||
#undef MAX_CHAR_UCS2
|
||||
#undef MAX_CHAR_UCS4
|
||||
|
||||
#endif /* STRINGLIB_SIZEOF_CHAR == 1 */
|
||||
|
140
third_party/python/Objects/stringlib/join.h
vendored
Normal file
140
third_party/python/Objects/stringlib/join.h
vendored
Normal file
|
@ -0,0 +1,140 @@
|
|||
/* stringlib: bytes joining implementation */
|
||||
|
||||
#if STRINGLIB_IS_UNICODE
|
||||
#error join.h only compatible with byte-wise strings
|
||||
#endif
|
||||
|
||||
Py_LOCAL_INLINE(PyObject *)
|
||||
STRINGLIB(bytes_join)(PyObject *sep, PyObject *iterable)
|
||||
{
|
||||
char *sepstr = STRINGLIB_STR(sep);
|
||||
const Py_ssize_t seplen = STRINGLIB_LEN(sep);
|
||||
PyObject *res = NULL;
|
||||
char *p;
|
||||
Py_ssize_t seqlen = 0;
|
||||
Py_ssize_t sz = 0;
|
||||
Py_ssize_t i, nbufs;
|
||||
PyObject *seq, *item;
|
||||
Py_buffer *buffers = NULL;
|
||||
#define NB_STATIC_BUFFERS 10
|
||||
Py_buffer static_buffers[NB_STATIC_BUFFERS];
|
||||
|
||||
seq = PySequence_Fast(iterable, "can only join an iterable");
|
||||
if (seq == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
seqlen = PySequence_Fast_GET_SIZE(seq);
|
||||
if (seqlen == 0) {
|
||||
Py_DECREF(seq);
|
||||
return STRINGLIB_NEW(NULL, 0);
|
||||
}
|
||||
#ifndef STRINGLIB_MUTABLE
|
||||
if (seqlen == 1) {
|
||||
item = PySequence_Fast_GET_ITEM(seq, 0);
|
||||
if (STRINGLIB_CHECK_EXACT(item)) {
|
||||
Py_INCREF(item);
|
||||
Py_DECREF(seq);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (seqlen > NB_STATIC_BUFFERS) {
|
||||
buffers = PyMem_NEW(Py_buffer, seqlen);
|
||||
if (buffers == NULL) {
|
||||
Py_DECREF(seq);
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
buffers = static_buffers;
|
||||
}
|
||||
|
||||
/* Here is the general case. Do a pre-pass to figure out the total
|
||||
* amount of space we'll need (sz), and see whether all arguments are
|
||||
* bytes-like.
|
||||
*/
|
||||
for (i = 0, nbufs = 0; i < seqlen; i++) {
|
||||
Py_ssize_t itemlen;
|
||||
item = PySequence_Fast_GET_ITEM(seq, i);
|
||||
if (PyBytes_CheckExact(item)) {
|
||||
/* Fast path. */
|
||||
Py_INCREF(item);
|
||||
buffers[i].obj = item;
|
||||
buffers[i].buf = PyBytes_AS_STRING(item);
|
||||
buffers[i].len = PyBytes_GET_SIZE(item);
|
||||
}
|
||||
else if (PyObject_GetBuffer(item, &buffers[i], PyBUF_SIMPLE) != 0) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"sequence item %zd: expected a bytes-like object, "
|
||||
"%.80s found",
|
||||
i, Py_TYPE(item)->tp_name);
|
||||
goto error;
|
||||
}
|
||||
nbufs = i + 1; /* for error cleanup */
|
||||
itemlen = buffers[i].len;
|
||||
if (itemlen > PY_SSIZE_T_MAX - sz) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"join() result is too long");
|
||||
goto error;
|
||||
}
|
||||
sz += itemlen;
|
||||
if (i != 0) {
|
||||
if (seplen > PY_SSIZE_T_MAX - sz) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"join() result is too long");
|
||||
goto error;
|
||||
}
|
||||
sz += seplen;
|
||||
}
|
||||
if (seqlen != PySequence_Fast_GET_SIZE(seq)) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"sequence changed size during iteration");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate result space. */
|
||||
res = STRINGLIB_NEW(NULL, sz);
|
||||
if (res == NULL)
|
||||
goto error;
|
||||
|
||||
/* Catenate everything. */
|
||||
p = STRINGLIB_STR(res);
|
||||
if (!seplen) {
|
||||
/* fast path */
|
||||
for (i = 0; i < nbufs; i++) {
|
||||
Py_ssize_t n = buffers[i].len;
|
||||
char *q = buffers[i].buf;
|
||||
memcpy(p, q, n);
|
||||
p += n;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
for (i = 0; i < nbufs; i++) {
|
||||
Py_ssize_t n;
|
||||
char *q;
|
||||
if (i) {
|
||||
memcpy(p, sepstr, seplen);
|
||||
p += seplen;
|
||||
}
|
||||
n = buffers[i].len;
|
||||
q = buffers[i].buf;
|
||||
memcpy(p, q, n);
|
||||
p += n;
|
||||
}
|
||||
goto done;
|
||||
|
||||
error:
|
||||
res = NULL;
|
||||
done:
|
||||
Py_DECREF(seq);
|
||||
for (i = 0; i < nbufs; i++)
|
||||
PyBuffer_Release(&buffers[i]);
|
||||
if (buffers != static_buffers)
|
||||
PyMem_FREE(buffers);
|
||||
return res;
|
||||
}
|
||||
|
||||
#undef NB_STATIC_BUFFERS
|
82
third_party/python/Objects/stringlib/localeutil.h
vendored
Normal file
82
third_party/python/Objects/stringlib/localeutil.h
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
/* _PyUnicode_InsertThousandsGrouping() helper functions */
|
||||
|
||||
typedef struct {
|
||||
const char *grouping;
|
||||
char previous;
|
||||
Py_ssize_t i; /* Where we're currently pointing in grouping. */
|
||||
} GroupGenerator;
|
||||
|
||||
|
||||
static void
|
||||
GroupGenerator_init(GroupGenerator *self, const char *grouping)
|
||||
{
|
||||
self->grouping = grouping;
|
||||
self->i = 0;
|
||||
self->previous = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Returns the next grouping, or 0 to signify end. */
|
||||
static Py_ssize_t
|
||||
GroupGenerator_next(GroupGenerator *self)
|
||||
{
|
||||
/* Note that we don't really do much error checking here. If a
|
||||
grouping string contains just CHAR_MAX, for example, then just
|
||||
terminate the generator. That shouldn't happen, but at least we
|
||||
fail gracefully. */
|
||||
switch (self->grouping[self->i]) {
|
||||
case 0:
|
||||
return self->previous;
|
||||
case CHAR_MAX:
|
||||
/* Stop the generator. */
|
||||
return 0;
|
||||
default: {
|
||||
char ch = self->grouping[self->i];
|
||||
self->previous = ch;
|
||||
self->i++;
|
||||
return (Py_ssize_t)ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Fill in some digits, leading zeros, and thousands separator. All
|
||||
are optional, depending on when we're called. */
|
||||
static void
|
||||
InsertThousandsGrouping_fill(_PyUnicodeWriter *writer, Py_ssize_t *buffer_pos,
|
||||
PyObject *digits, Py_ssize_t *digits_pos,
|
||||
Py_ssize_t n_chars, Py_ssize_t n_zeros,
|
||||
PyObject *thousands_sep, Py_ssize_t thousands_sep_len,
|
||||
Py_UCS4 *maxchar)
|
||||
{
|
||||
if (!writer) {
|
||||
/* if maxchar > 127, maxchar is already set */
|
||||
if (*maxchar == 127 && thousands_sep) {
|
||||
Py_UCS4 maxchar2 = PyUnicode_MAX_CHAR_VALUE(thousands_sep);
|
||||
*maxchar = Py_MAX(*maxchar, maxchar2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (thousands_sep) {
|
||||
*buffer_pos -= thousands_sep_len;
|
||||
|
||||
/* Copy the thousands_sep chars into the buffer. */
|
||||
_PyUnicode_FastCopyCharacters(writer->buffer, *buffer_pos,
|
||||
thousands_sep, 0,
|
||||
thousands_sep_len);
|
||||
}
|
||||
|
||||
*buffer_pos -= n_chars;
|
||||
*digits_pos -= n_chars;
|
||||
_PyUnicode_FastCopyCharacters(writer->buffer, *buffer_pos,
|
||||
digits, *digits_pos,
|
||||
n_chars);
|
||||
|
||||
if (n_zeros) {
|
||||
*buffer_pos -= n_zeros;
|
||||
enum PyUnicode_Kind kind = PyUnicode_KIND(writer->buffer);
|
||||
void *data = PyUnicode_DATA(writer->buffer);
|
||||
FILL(kind, data, '0', *buffer_pos, n_zeros);
|
||||
}
|
||||
}
|
116
third_party/python/Objects/stringlib/partition.h
vendored
Normal file
116
third_party/python/Objects/stringlib/partition.h
vendored
Normal file
|
@ -0,0 +1,116 @@
|
|||
/* stringlib: partition implementation */
|
||||
|
||||
#ifndef STRINGLIB_FASTSEARCH_H
|
||||
#error must include "stringlib/fastsearch.h" before including this module
|
||||
#endif
|
||||
|
||||
Py_LOCAL_INLINE(PyObject*)
|
||||
STRINGLIB(partition)(PyObject* str_obj,
|
||||
const STRINGLIB_CHAR* str, Py_ssize_t str_len,
|
||||
PyObject* sep_obj,
|
||||
const STRINGLIB_CHAR* sep, Py_ssize_t sep_len)
|
||||
{
|
||||
PyObject* out;
|
||||
Py_ssize_t pos;
|
||||
|
||||
if (sep_len == 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "empty separator");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out = PyTuple_New(3);
|
||||
if (!out)
|
||||
return NULL;
|
||||
|
||||
pos = FASTSEARCH(str, str_len, sep, sep_len, -1, FAST_SEARCH);
|
||||
|
||||
if (pos < 0) {
|
||||
#if STRINGLIB_MUTABLE
|
||||
PyTuple_SET_ITEM(out, 0, STRINGLIB_NEW(str, str_len));
|
||||
PyTuple_SET_ITEM(out, 1, STRINGLIB_NEW(NULL, 0));
|
||||
PyTuple_SET_ITEM(out, 2, STRINGLIB_NEW(NULL, 0));
|
||||
|
||||
if (PyErr_Occurred()) {
|
||||
Py_DECREF(out);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
Py_INCREF(str_obj);
|
||||
PyTuple_SET_ITEM(out, 0, (PyObject*) str_obj);
|
||||
Py_INCREF(STRINGLIB_EMPTY);
|
||||
PyTuple_SET_ITEM(out, 1, (PyObject*) STRINGLIB_EMPTY);
|
||||
Py_INCREF(STRINGLIB_EMPTY);
|
||||
PyTuple_SET_ITEM(out, 2, (PyObject*) STRINGLIB_EMPTY);
|
||||
#endif
|
||||
return out;
|
||||
}
|
||||
|
||||
PyTuple_SET_ITEM(out, 0, STRINGLIB_NEW(str, pos));
|
||||
Py_INCREF(sep_obj);
|
||||
PyTuple_SET_ITEM(out, 1, sep_obj);
|
||||
pos += sep_len;
|
||||
PyTuple_SET_ITEM(out, 2, STRINGLIB_NEW(str + pos, str_len - pos));
|
||||
|
||||
if (PyErr_Occurred()) {
|
||||
Py_DECREF(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Py_LOCAL_INLINE(PyObject*)
|
||||
STRINGLIB(rpartition)(PyObject* str_obj,
|
||||
const STRINGLIB_CHAR* str, Py_ssize_t str_len,
|
||||
PyObject* sep_obj,
|
||||
const STRINGLIB_CHAR* sep, Py_ssize_t sep_len)
|
||||
{
|
||||
PyObject* out;
|
||||
Py_ssize_t pos;
|
||||
|
||||
if (sep_len == 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "empty separator");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out = PyTuple_New(3);
|
||||
if (!out)
|
||||
return NULL;
|
||||
|
||||
pos = FASTSEARCH(str, str_len, sep, sep_len, -1, FAST_RSEARCH);
|
||||
|
||||
if (pos < 0) {
|
||||
#if STRINGLIB_MUTABLE
|
||||
PyTuple_SET_ITEM(out, 0, STRINGLIB_NEW(NULL, 0));
|
||||
PyTuple_SET_ITEM(out, 1, STRINGLIB_NEW(NULL, 0));
|
||||
PyTuple_SET_ITEM(out, 2, STRINGLIB_NEW(str, str_len));
|
||||
|
||||
if (PyErr_Occurred()) {
|
||||
Py_DECREF(out);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
Py_INCREF(STRINGLIB_EMPTY);
|
||||
PyTuple_SET_ITEM(out, 0, (PyObject*) STRINGLIB_EMPTY);
|
||||
Py_INCREF(STRINGLIB_EMPTY);
|
||||
PyTuple_SET_ITEM(out, 1, (PyObject*) STRINGLIB_EMPTY);
|
||||
Py_INCREF(str_obj);
|
||||
PyTuple_SET_ITEM(out, 2, (PyObject*) str_obj);
|
||||
#endif
|
||||
return out;
|
||||
}
|
||||
|
||||
PyTuple_SET_ITEM(out, 0, STRINGLIB_NEW(str, pos));
|
||||
Py_INCREF(sep_obj);
|
||||
PyTuple_SET_ITEM(out, 1, sep_obj);
|
||||
pos += sep_len;
|
||||
PyTuple_SET_ITEM(out, 2, STRINGLIB_NEW(str + pos, str_len - pos));
|
||||
|
||||
if (PyErr_Occurred()) {
|
||||
Py_DECREF(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
53
third_party/python/Objects/stringlib/replace.h
vendored
Normal file
53
third_party/python/Objects/stringlib/replace.h
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* stringlib: replace implementation */
|
||||
|
||||
#ifndef STRINGLIB_FASTSEARCH_H
|
||||
#error must include "stringlib/fastsearch.h" before including this module
|
||||
#endif
|
||||
|
||||
Py_LOCAL_INLINE(void)
|
||||
STRINGLIB(replace_1char_inplace)(STRINGLIB_CHAR* s, STRINGLIB_CHAR* end,
|
||||
Py_UCS4 u1, Py_UCS4 u2, Py_ssize_t maxcount)
|
||||
{
|
||||
*s = u2;
|
||||
while (--maxcount && ++s != end) {
|
||||
/* Find the next character to be replaced.
|
||||
|
||||
If it occurs often, it is faster to scan for it using an inline
|
||||
loop. If it occurs seldom, it is faster to scan for it using a
|
||||
function call; the overhead of the function call is amortized
|
||||
across the many characters that call covers. We start with an
|
||||
inline loop and use a heuristic to determine whether to fall back
|
||||
to a function call. */
|
||||
if (*s != u1) {
|
||||
int attempts = 10;
|
||||
/* search u1 in a dummy loop */
|
||||
while (1) {
|
||||
if (++s == end)
|
||||
return;
|
||||
if (*s == u1)
|
||||
break;
|
||||
if (!--attempts) {
|
||||
/* if u1 was not found for attempts iterations,
|
||||
use FASTSEARCH() or memchr() */
|
||||
#if STRINGLIB_SIZEOF_CHAR == 1
|
||||
s++;
|
||||
s = memchr(s, u1, end - s);
|
||||
if (s == NULL)
|
||||
return;
|
||||
#else
|
||||
Py_ssize_t i;
|
||||
STRINGLIB_CHAR ch1 = (STRINGLIB_CHAR) u1;
|
||||
s++;
|
||||
i = FASTSEARCH(s, end - s, &ch1, 1, 0, FAST_SEARCH);
|
||||
if (i < 0)
|
||||
return;
|
||||
s += i;
|
||||
#endif
|
||||
/* restart the dummy loop */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*s = u2;
|
||||
}
|
||||
}
|
390
third_party/python/Objects/stringlib/split.h
vendored
Normal file
390
third_party/python/Objects/stringlib/split.h
vendored
Normal file
|
@ -0,0 +1,390 @@
|
|||
/* stringlib: split implementation */
|
||||
|
||||
#ifndef STRINGLIB_FASTSEARCH_H
|
||||
#error must include "stringlib/fastsearch.h" before including this module
|
||||
#endif
|
||||
|
||||
/* Overallocate the initial list to reduce the number of reallocs for small
|
||||
split sizes. Eg, "A A A A A A A A A A".split() (10 elements) has three
|
||||
resizes, to sizes 4, 8, then 16. Most observed string splits are for human
|
||||
text (roughly 11 words per line) and field delimited data (usually 1-10
|
||||
fields). For large strings the split algorithms are bandwidth limited
|
||||
so increasing the preallocation likely will not improve things.*/
|
||||
|
||||
#define MAX_PREALLOC 12
|
||||
|
||||
/* 5 splits gives 6 elements */
|
||||
#define PREALLOC_SIZE(maxsplit) \
|
||||
(maxsplit >= MAX_PREALLOC ? MAX_PREALLOC : maxsplit+1)
|
||||
|
||||
#define SPLIT_APPEND(data, left, right) \
|
||||
sub = STRINGLIB_NEW((data) + (left), \
|
||||
(right) - (left)); \
|
||||
if (sub == NULL) \
|
||||
goto onError; \
|
||||
if (PyList_Append(list, sub)) { \
|
||||
Py_DECREF(sub); \
|
||||
goto onError; \
|
||||
} \
|
||||
else \
|
||||
Py_DECREF(sub);
|
||||
|
||||
#define SPLIT_ADD(data, left, right) { \
|
||||
sub = STRINGLIB_NEW((data) + (left), \
|
||||
(right) - (left)); \
|
||||
if (sub == NULL) \
|
||||
goto onError; \
|
||||
if (count < MAX_PREALLOC) { \
|
||||
PyList_SET_ITEM(list, count, sub); \
|
||||
} else { \
|
||||
if (PyList_Append(list, sub)) { \
|
||||
Py_DECREF(sub); \
|
||||
goto onError; \
|
||||
} \
|
||||
else \
|
||||
Py_DECREF(sub); \
|
||||
} \
|
||||
count++; }
|
||||
|
||||
|
||||
/* Always force the list to the expected size. */
|
||||
#define FIX_PREALLOC_SIZE(list) Py_SIZE(list) = count
|
||||
|
||||
Py_LOCAL_INLINE(PyObject *)
|
||||
STRINGLIB(split_whitespace)(PyObject* str_obj,
|
||||
const STRINGLIB_CHAR* str, Py_ssize_t str_len,
|
||||
Py_ssize_t maxcount)
|
||||
{
|
||||
Py_ssize_t i, j, count=0;
|
||||
PyObject *list = PyList_New(PREALLOC_SIZE(maxcount));
|
||||
PyObject *sub;
|
||||
|
||||
if (list == NULL)
|
||||
return NULL;
|
||||
|
||||
i = j = 0;
|
||||
while (maxcount-- > 0) {
|
||||
while (i < str_len && STRINGLIB_ISSPACE(str[i]))
|
||||
i++;
|
||||
if (i == str_len) break;
|
||||
j = i; i++;
|
||||
while (i < str_len && !STRINGLIB_ISSPACE(str[i]))
|
||||
i++;
|
||||
#ifndef STRINGLIB_MUTABLE
|
||||
if (j == 0 && i == str_len && STRINGLIB_CHECK_EXACT(str_obj)) {
|
||||
/* No whitespace in str_obj, so just use it as list[0] */
|
||||
Py_INCREF(str_obj);
|
||||
PyList_SET_ITEM(list, 0, (PyObject *)str_obj);
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
SPLIT_ADD(str, j, i);
|
||||
}
|
||||
|
||||
if (i < str_len) {
|
||||
/* Only occurs when maxcount was reached */
|
||||
/* Skip any remaining whitespace and copy to end of string */
|
||||
while (i < str_len && STRINGLIB_ISSPACE(str[i]))
|
||||
i++;
|
||||
if (i != str_len)
|
||||
SPLIT_ADD(str, i, str_len);
|
||||
}
|
||||
FIX_PREALLOC_SIZE(list);
|
||||
return list;
|
||||
|
||||
onError:
|
||||
Py_DECREF(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_LOCAL_INLINE(PyObject *)
|
||||
STRINGLIB(split_char)(PyObject* str_obj,
|
||||
const STRINGLIB_CHAR* str, Py_ssize_t str_len,
|
||||
const STRINGLIB_CHAR ch,
|
||||
Py_ssize_t maxcount)
|
||||
{
|
||||
Py_ssize_t i, j, count=0;
|
||||
PyObject *list = PyList_New(PREALLOC_SIZE(maxcount));
|
||||
PyObject *sub;
|
||||
|
||||
if (list == NULL)
|
||||
return NULL;
|
||||
|
||||
i = j = 0;
|
||||
while ((j < str_len) && (maxcount-- > 0)) {
|
||||
for(; j < str_len; j++) {
|
||||
/* I found that using memchr makes no difference */
|
||||
if (str[j] == ch) {
|
||||
SPLIT_ADD(str, i, j);
|
||||
i = j = j + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef STRINGLIB_MUTABLE
|
||||
if (count == 0 && STRINGLIB_CHECK_EXACT(str_obj)) {
|
||||
/* ch not in str_obj, so just use str_obj as list[0] */
|
||||
Py_INCREF(str_obj);
|
||||
PyList_SET_ITEM(list, 0, (PyObject *)str_obj);
|
||||
count++;
|
||||
} else
|
||||
#endif
|
||||
if (i <= str_len) {
|
||||
SPLIT_ADD(str, i, str_len);
|
||||
}
|
||||
FIX_PREALLOC_SIZE(list);
|
||||
return list;
|
||||
|
||||
onError:
|
||||
Py_DECREF(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_LOCAL_INLINE(PyObject *)
|
||||
STRINGLIB(split)(PyObject* str_obj,
|
||||
const STRINGLIB_CHAR* str, Py_ssize_t str_len,
|
||||
const STRINGLIB_CHAR* sep, Py_ssize_t sep_len,
|
||||
Py_ssize_t maxcount)
|
||||
{
|
||||
Py_ssize_t i, j, pos, count=0;
|
||||
PyObject *list, *sub;
|
||||
|
||||
if (sep_len == 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "empty separator");
|
||||
return NULL;
|
||||
}
|
||||
else if (sep_len == 1)
|
||||
return STRINGLIB(split_char)(str_obj, str, str_len, sep[0], maxcount);
|
||||
|
||||
list = PyList_New(PREALLOC_SIZE(maxcount));
|
||||
if (list == NULL)
|
||||
return NULL;
|
||||
|
||||
i = j = 0;
|
||||
while (maxcount-- > 0) {
|
||||
pos = FASTSEARCH(str+i, str_len-i, sep, sep_len, -1, FAST_SEARCH);
|
||||
if (pos < 0)
|
||||
break;
|
||||
j = i + pos;
|
||||
SPLIT_ADD(str, i, j);
|
||||
i = j + sep_len;
|
||||
}
|
||||
#ifndef STRINGLIB_MUTABLE
|
||||
if (count == 0 && STRINGLIB_CHECK_EXACT(str_obj)) {
|
||||
/* No match in str_obj, so just use it as list[0] */
|
||||
Py_INCREF(str_obj);
|
||||
PyList_SET_ITEM(list, 0, (PyObject *)str_obj);
|
||||
count++;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
SPLIT_ADD(str, i, str_len);
|
||||
}
|
||||
FIX_PREALLOC_SIZE(list);
|
||||
return list;
|
||||
|
||||
onError:
|
||||
Py_DECREF(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_LOCAL_INLINE(PyObject *)
|
||||
STRINGLIB(rsplit_whitespace)(PyObject* str_obj,
|
||||
const STRINGLIB_CHAR* str, Py_ssize_t str_len,
|
||||
Py_ssize_t maxcount)
|
||||
{
|
||||
Py_ssize_t i, j, count=0;
|
||||
PyObject *list = PyList_New(PREALLOC_SIZE(maxcount));
|
||||
PyObject *sub;
|
||||
|
||||
if (list == NULL)
|
||||
return NULL;
|
||||
|
||||
i = j = str_len - 1;
|
||||
while (maxcount-- > 0) {
|
||||
while (i >= 0 && STRINGLIB_ISSPACE(str[i]))
|
||||
i--;
|
||||
if (i < 0) break;
|
||||
j = i; i--;
|
||||
while (i >= 0 && !STRINGLIB_ISSPACE(str[i]))
|
||||
i--;
|
||||
#ifndef STRINGLIB_MUTABLE
|
||||
if (j == str_len - 1 && i < 0 && STRINGLIB_CHECK_EXACT(str_obj)) {
|
||||
/* No whitespace in str_obj, so just use it as list[0] */
|
||||
Py_INCREF(str_obj);
|
||||
PyList_SET_ITEM(list, 0, (PyObject *)str_obj);
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
SPLIT_ADD(str, i + 1, j + 1);
|
||||
}
|
||||
|
||||
if (i >= 0) {
|
||||
/* Only occurs when maxcount was reached */
|
||||
/* Skip any remaining whitespace and copy to beginning of string */
|
||||
while (i >= 0 && STRINGLIB_ISSPACE(str[i]))
|
||||
i--;
|
||||
if (i >= 0)
|
||||
SPLIT_ADD(str, 0, i + 1);
|
||||
}
|
||||
FIX_PREALLOC_SIZE(list);
|
||||
if (PyList_Reverse(list) < 0)
|
||||
goto onError;
|
||||
return list;
|
||||
|
||||
onError:
|
||||
Py_DECREF(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_LOCAL_INLINE(PyObject *)
|
||||
STRINGLIB(rsplit_char)(PyObject* str_obj,
|
||||
const STRINGLIB_CHAR* str, Py_ssize_t str_len,
|
||||
const STRINGLIB_CHAR ch,
|
||||
Py_ssize_t maxcount)
|
||||
{
|
||||
Py_ssize_t i, j, count=0;
|
||||
PyObject *list = PyList_New(PREALLOC_SIZE(maxcount));
|
||||
PyObject *sub;
|
||||
|
||||
if (list == NULL)
|
||||
return NULL;
|
||||
|
||||
i = j = str_len - 1;
|
||||
while ((i >= 0) && (maxcount-- > 0)) {
|
||||
for(; i >= 0; i--) {
|
||||
if (str[i] == ch) {
|
||||
SPLIT_ADD(str, i + 1, j + 1);
|
||||
j = i = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef STRINGLIB_MUTABLE
|
||||
if (count == 0 && STRINGLIB_CHECK_EXACT(str_obj)) {
|
||||
/* ch not in str_obj, so just use str_obj as list[0] */
|
||||
Py_INCREF(str_obj);
|
||||
PyList_SET_ITEM(list, 0, (PyObject *)str_obj);
|
||||
count++;
|
||||
} else
|
||||
#endif
|
||||
if (j >= -1) {
|
||||
SPLIT_ADD(str, 0, j + 1);
|
||||
}
|
||||
FIX_PREALLOC_SIZE(list);
|
||||
if (PyList_Reverse(list) < 0)
|
||||
goto onError;
|
||||
return list;
|
||||
|
||||
onError:
|
||||
Py_DECREF(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_LOCAL_INLINE(PyObject *)
|
||||
STRINGLIB(rsplit)(PyObject* str_obj,
|
||||
const STRINGLIB_CHAR* str, Py_ssize_t str_len,
|
||||
const STRINGLIB_CHAR* sep, Py_ssize_t sep_len,
|
||||
Py_ssize_t maxcount)
|
||||
{
|
||||
Py_ssize_t j, pos, count=0;
|
||||
PyObject *list, *sub;
|
||||
|
||||
if (sep_len == 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "empty separator");
|
||||
return NULL;
|
||||
}
|
||||
else if (sep_len == 1)
|
||||
return STRINGLIB(rsplit_char)(str_obj, str, str_len, sep[0], maxcount);
|
||||
|
||||
list = PyList_New(PREALLOC_SIZE(maxcount));
|
||||
if (list == NULL)
|
||||
return NULL;
|
||||
|
||||
j = str_len;
|
||||
while (maxcount-- > 0) {
|
||||
pos = FASTSEARCH(str, j, sep, sep_len, -1, FAST_RSEARCH);
|
||||
if (pos < 0)
|
||||
break;
|
||||
SPLIT_ADD(str, pos + sep_len, j);
|
||||
j = pos;
|
||||
}
|
||||
#ifndef STRINGLIB_MUTABLE
|
||||
if (count == 0 && STRINGLIB_CHECK_EXACT(str_obj)) {
|
||||
/* No match in str_obj, so just use it as list[0] */
|
||||
Py_INCREF(str_obj);
|
||||
PyList_SET_ITEM(list, 0, (PyObject *)str_obj);
|
||||
count++;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
SPLIT_ADD(str, 0, j);
|
||||
}
|
||||
FIX_PREALLOC_SIZE(list);
|
||||
if (PyList_Reverse(list) < 0)
|
||||
goto onError;
|
||||
return list;
|
||||
|
||||
onError:
|
||||
Py_DECREF(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_LOCAL_INLINE(PyObject *)
|
||||
STRINGLIB(splitlines)(PyObject* str_obj,
|
||||
const STRINGLIB_CHAR* str, Py_ssize_t str_len,
|
||||
int keepends)
|
||||
{
|
||||
/* This does not use the preallocated list because splitlines is
|
||||
usually run with hundreds of newlines. The overhead of
|
||||
switching between PyList_SET_ITEM and append causes about a
|
||||
2-3% slowdown for that common case. A smarter implementation
|
||||
could move the if check out, so the SET_ITEMs are done first
|
||||
and the appends only done when the prealloc buffer is full.
|
||||
That's too much work for little gain.*/
|
||||
|
||||
Py_ssize_t i;
|
||||
Py_ssize_t j;
|
||||
PyObject *list = PyList_New(0);
|
||||
PyObject *sub;
|
||||
|
||||
if (list == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = j = 0; i < str_len; ) {
|
||||
Py_ssize_t eol;
|
||||
|
||||
/* Find a line and append it */
|
||||
while (i < str_len && !STRINGLIB_ISLINEBREAK(str[i]))
|
||||
i++;
|
||||
|
||||
/* Skip the line break reading CRLF as one line break */
|
||||
eol = i;
|
||||
if (i < str_len) {
|
||||
if (str[i] == '\r' && i + 1 < str_len && str[i+1] == '\n')
|
||||
i += 2;
|
||||
else
|
||||
i++;
|
||||
if (keepends)
|
||||
eol = i;
|
||||
}
|
||||
#ifndef STRINGLIB_MUTABLE
|
||||
if (j == 0 && eol == str_len && STRINGLIB_CHECK_EXACT(str_obj)) {
|
||||
/* No linebreak in str_obj, so just use it as list[0] */
|
||||
if (PyList_Append(list, str_obj))
|
||||
goto onError;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
SPLIT_APPEND(str, j, eol);
|
||||
j = i;
|
||||
}
|
||||
return list;
|
||||
|
||||
onError:
|
||||
Py_DECREF(list);
|
||||
return NULL;
|
||||
}
|
||||
|
28
third_party/python/Objects/stringlib/stringdefs.h
vendored
Normal file
28
third_party/python/Objects/stringlib/stringdefs.h
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef STRINGLIB_STRINGDEFS_H
|
||||
#define STRINGLIB_STRINGDEFS_H
|
||||
|
||||
/* this is sort of a hack. there's at least one place (formatting
|
||||
floats) where some stringlib code takes a different path if it's
|
||||
compiled as unicode. */
|
||||
#define STRINGLIB_IS_UNICODE 0
|
||||
|
||||
#define FASTSEARCH fastsearch
|
||||
#define STRINGLIB(F) stringlib_##F
|
||||
#define STRINGLIB_OBJECT PyBytesObject
|
||||
#define STRINGLIB_SIZEOF_CHAR 1
|
||||
#define STRINGLIB_CHAR char
|
||||
#define STRINGLIB_TYPE_NAME "string"
|
||||
#define STRINGLIB_PARSE_CODE "S"
|
||||
#define STRINGLIB_EMPTY nullstring
|
||||
#define STRINGLIB_ISSPACE Py_ISSPACE
|
||||
#define STRINGLIB_ISLINEBREAK(x) ((x == '\n') || (x == '\r'))
|
||||
#define STRINGLIB_ISDECIMAL(x) ((x >= '0') && (x <= '9'))
|
||||
#define STRINGLIB_TODECIMAL(x) (STRINGLIB_ISDECIMAL(x) ? (x - '0') : -1)
|
||||
#define STRINGLIB_STR PyBytes_AS_STRING
|
||||
#define STRINGLIB_LEN PyBytes_GET_SIZE
|
||||
#define STRINGLIB_NEW PyBytes_FromStringAndSize
|
||||
#define STRINGLIB_CHECK PyBytes_Check
|
||||
#define STRINGLIB_CHECK_EXACT PyBytes_CheckExact
|
||||
#define STRINGLIB_TOSTR PyObject_Str
|
||||
#define STRINGLIB_TOASCII PyObject_Repr
|
||||
#endif /* !STRINGLIB_STRINGDEFS_H */
|
701
third_party/python/Objects/stringlib/transmogrify.h
vendored
Normal file
701
third_party/python/Objects/stringlib/transmogrify.h
vendored
Normal file
|
@ -0,0 +1,701 @@
|
|||
#if STRINGLIB_IS_UNICODE
|
||||
# error "transmogrify.h only compatible with byte-wise strings"
|
||||
#endif
|
||||
|
||||
/* the more complicated methods. parts of these should be pulled out into the
|
||||
shared code in bytes_methods.c to cut down on duplicate code bloat. */
|
||||
|
||||
static inline PyObject *
|
||||
return_self(PyObject *self)
|
||||
{
|
||||
#if !STRINGLIB_MUTABLE
|
||||
if (STRINGLIB_CHECK_EXACT(self)) {
|
||||
Py_INCREF(self);
|
||||
return self;
|
||||
}
|
||||
#endif
|
||||
return STRINGLIB_NEW(STRINGLIB_STR(self), STRINGLIB_LEN(self));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
stringlib_expandtabs(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
const char *e, *p;
|
||||
char *q;
|
||||
Py_ssize_t i, j;
|
||||
PyObject *u;
|
||||
static char *kwlist[] = {"tabsize", 0};
|
||||
int tabsize = 8;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:expandtabs",
|
||||
kwlist, &tabsize))
|
||||
return NULL;
|
||||
|
||||
/* First pass: determine size of output string */
|
||||
i = j = 0;
|
||||
e = STRINGLIB_STR(self) + STRINGLIB_LEN(self);
|
||||
for (p = STRINGLIB_STR(self); p < e; p++) {
|
||||
if (*p == '\t') {
|
||||
if (tabsize > 0) {
|
||||
Py_ssize_t incr = tabsize - (j % tabsize);
|
||||
if (j > PY_SSIZE_T_MAX - incr)
|
||||
goto overflow;
|
||||
j += incr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (j > PY_SSIZE_T_MAX - 1)
|
||||
goto overflow;
|
||||
j++;
|
||||
if (*p == '\n' || *p == '\r') {
|
||||
if (i > PY_SSIZE_T_MAX - j)
|
||||
goto overflow;
|
||||
i += j;
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i > PY_SSIZE_T_MAX - j)
|
||||
goto overflow;
|
||||
|
||||
/* Second pass: create output string and fill it */
|
||||
u = STRINGLIB_NEW(NULL, i + j);
|
||||
if (!u)
|
||||
return NULL;
|
||||
|
||||
j = 0;
|
||||
q = STRINGLIB_STR(u);
|
||||
|
||||
for (p = STRINGLIB_STR(self); p < e; p++) {
|
||||
if (*p == '\t') {
|
||||
if (tabsize > 0) {
|
||||
i = tabsize - (j % tabsize);
|
||||
j += i;
|
||||
while (i--)
|
||||
*q++ = ' ';
|
||||
}
|
||||
}
|
||||
else {
|
||||
j++;
|
||||
*q++ = *p;
|
||||
if (*p == '\n' || *p == '\r')
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return u;
|
||||
overflow:
|
||||
PyErr_SetString(PyExc_OverflowError, "result too long");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
pad(PyObject *self, Py_ssize_t left, Py_ssize_t right, char fill)
|
||||
{
|
||||
PyObject *u;
|
||||
|
||||
if (left < 0)
|
||||
left = 0;
|
||||
if (right < 0)
|
||||
right = 0;
|
||||
|
||||
if (left == 0 && right == 0) {
|
||||
return return_self(self);
|
||||
}
|
||||
|
||||
u = STRINGLIB_NEW(NULL, left + STRINGLIB_LEN(self) + right);
|
||||
if (u) {
|
||||
if (left)
|
||||
memset(STRINGLIB_STR(u), fill, left);
|
||||
memcpy(STRINGLIB_STR(u) + left,
|
||||
STRINGLIB_STR(self),
|
||||
STRINGLIB_LEN(self));
|
||||
if (right)
|
||||
memset(STRINGLIB_STR(u) + left + STRINGLIB_LEN(self),
|
||||
fill, right);
|
||||
}
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
stringlib_ljust(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t width;
|
||||
char fillchar = ' ';
|
||||
|
||||
if (!PyArg_ParseTuple(args, "n|c:ljust", &width, &fillchar))
|
||||
return NULL;
|
||||
|
||||
if (STRINGLIB_LEN(self) >= width) {
|
||||
return return_self(self);
|
||||
}
|
||||
|
||||
return pad(self, 0, width - STRINGLIB_LEN(self), fillchar);
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
stringlib_rjust(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t width;
|
||||
char fillchar = ' ';
|
||||
|
||||
if (!PyArg_ParseTuple(args, "n|c:rjust", &width, &fillchar))
|
||||
return NULL;
|
||||
|
||||
if (STRINGLIB_LEN(self) >= width) {
|
||||
return return_self(self);
|
||||
}
|
||||
|
||||
return pad(self, width - STRINGLIB_LEN(self), 0, fillchar);
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
stringlib_center(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t marg, left;
|
||||
Py_ssize_t width;
|
||||
char fillchar = ' ';
|
||||
|
||||
if (!PyArg_ParseTuple(args, "n|c:center", &width, &fillchar))
|
||||
return NULL;
|
||||
|
||||
if (STRINGLIB_LEN(self) >= width) {
|
||||
return return_self(self);
|
||||
}
|
||||
|
||||
marg = width - STRINGLIB_LEN(self);
|
||||
left = marg / 2 + (marg & width & 1);
|
||||
|
||||
return pad(self, left, marg - left, fillchar);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
stringlib_zfill(PyObject *self, PyObject *args)
|
||||
{
|
||||
Py_ssize_t fill;
|
||||
PyObject *s;
|
||||
char *p;
|
||||
Py_ssize_t width;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "n:zfill", &width))
|
||||
return NULL;
|
||||
|
||||
if (STRINGLIB_LEN(self) >= width) {
|
||||
return return_self(self);
|
||||
}
|
||||
|
||||
fill = width - STRINGLIB_LEN(self);
|
||||
|
||||
s = pad(self, fill, 0, '0');
|
||||
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
p = STRINGLIB_STR(s);
|
||||
if (p[fill] == '+' || p[fill] == '-') {
|
||||
/* move sign to beginning of string */
|
||||
p[0] = p[fill];
|
||||
p[fill] = '0';
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/* find and count characters and substrings */
|
||||
|
||||
#define findchar(target, target_len, c) \
|
||||
((char *)memchr((const void *)(target), c, target_len))
|
||||
|
||||
|
||||
static Py_ssize_t
|
||||
countchar(const char *target, Py_ssize_t target_len, char c,
|
||||
Py_ssize_t maxcount)
|
||||
{
|
||||
Py_ssize_t count = 0;
|
||||
const char *start = target;
|
||||
const char *end = target + target_len;
|
||||
|
||||
while ((start = findchar(start, end - start, c)) != NULL) {
|
||||
count++;
|
||||
if (count >= maxcount)
|
||||
break;
|
||||
start += 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/* Algorithms for different cases of string replacement */
|
||||
|
||||
/* len(self)>=1, from="", len(to)>=1, maxcount>=1 */
|
||||
static PyObject *
|
||||
stringlib_replace_interleave(PyObject *self,
|
||||
const char *to_s, Py_ssize_t to_len,
|
||||
Py_ssize_t maxcount)
|
||||
{
|
||||
const char *self_s;
|
||||
char *result_s;
|
||||
Py_ssize_t self_len, result_len;
|
||||
Py_ssize_t count, i;
|
||||
PyObject *result;
|
||||
|
||||
self_len = STRINGLIB_LEN(self);
|
||||
|
||||
/* 1 at the end plus 1 after every character;
|
||||
count = min(maxcount, self_len + 1) */
|
||||
if (maxcount <= self_len) {
|
||||
count = maxcount;
|
||||
}
|
||||
else {
|
||||
/* Can't overflow: self_len + 1 <= maxcount <= PY_SSIZE_T_MAX. */
|
||||
count = self_len + 1;
|
||||
}
|
||||
|
||||
/* Check for overflow */
|
||||
/* result_len = count * to_len + self_len; */
|
||||
assert(count > 0);
|
||||
if (to_len > (PY_SSIZE_T_MAX - self_len) / count) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"replace bytes are too long");
|
||||
return NULL;
|
||||
}
|
||||
result_len = count * to_len + self_len;
|
||||
result = STRINGLIB_NEW(NULL, result_len);
|
||||
if (result == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self_s = STRINGLIB_STR(self);
|
||||
result_s = STRINGLIB_STR(result);
|
||||
|
||||
if (to_len > 1) {
|
||||
/* Lay the first one down (guaranteed this will occur) */
|
||||
memcpy(result_s, to_s, to_len);
|
||||
result_s += to_len;
|
||||
count -= 1;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
*result_s++ = *self_s++;
|
||||
memcpy(result_s, to_s, to_len);
|
||||
result_s += to_len;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result_s[0] = to_s[0];
|
||||
result_s += to_len;
|
||||
count -= 1;
|
||||
for (i = 0; i < count; i++) {
|
||||
*result_s++ = *self_s++;
|
||||
result_s[0] = to_s[0];
|
||||
result_s += to_len;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the rest of the original string */
|
||||
memcpy(result_s, self_s, self_len - i);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Special case for deleting a single character */
|
||||
/* len(self)>=1, len(from)==1, to="", maxcount>=1 */
|
||||
static PyObject *
|
||||
stringlib_replace_delete_single_character(PyObject *self,
|
||||
char from_c, Py_ssize_t maxcount)
|
||||
{
|
||||
const char *self_s, *start, *next, *end;
|
||||
char *result_s;
|
||||
Py_ssize_t self_len, result_len;
|
||||
Py_ssize_t count;
|
||||
PyObject *result;
|
||||
|
||||
self_len = STRINGLIB_LEN(self);
|
||||
self_s = STRINGLIB_STR(self);
|
||||
|
||||
count = countchar(self_s, self_len, from_c, maxcount);
|
||||
if (count == 0) {
|
||||
return return_self(self);
|
||||
}
|
||||
|
||||
result_len = self_len - count; /* from_len == 1 */
|
||||
assert(result_len>=0);
|
||||
|
||||
result = STRINGLIB_NEW(NULL, result_len);
|
||||
if (result == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
result_s = STRINGLIB_STR(result);
|
||||
|
||||
start = self_s;
|
||||
end = self_s + self_len;
|
||||
while (count-- > 0) {
|
||||
next = findchar(start, end - start, from_c);
|
||||
if (next == NULL)
|
||||
break;
|
||||
memcpy(result_s, start, next - start);
|
||||
result_s += (next - start);
|
||||
start = next + 1;
|
||||
}
|
||||
memcpy(result_s, start, end - start);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* len(self)>=1, len(from)>=2, to="", maxcount>=1 */
|
||||
|
||||
static PyObject *
|
||||
stringlib_replace_delete_substring(PyObject *self,
|
||||
const char *from_s, Py_ssize_t from_len,
|
||||
Py_ssize_t maxcount)
|
||||
{
|
||||
const char *self_s, *start, *next, *end;
|
||||
char *result_s;
|
||||
Py_ssize_t self_len, result_len;
|
||||
Py_ssize_t count, offset;
|
||||
PyObject *result;
|
||||
|
||||
self_len = STRINGLIB_LEN(self);
|
||||
self_s = STRINGLIB_STR(self);
|
||||
|
||||
count = stringlib_count(self_s, self_len,
|
||||
from_s, from_len,
|
||||
maxcount);
|
||||
|
||||
if (count == 0) {
|
||||
/* no matches */
|
||||
return return_self(self);
|
||||
}
|
||||
|
||||
result_len = self_len - (count * from_len);
|
||||
assert (result_len>=0);
|
||||
|
||||
result = STRINGLIB_NEW(NULL, result_len);
|
||||
if (result == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
result_s = STRINGLIB_STR(result);
|
||||
|
||||
start = self_s;
|
||||
end = self_s + self_len;
|
||||
while (count-- > 0) {
|
||||
offset = stringlib_find(start, end - start,
|
||||
from_s, from_len,
|
||||
0);
|
||||
if (offset == -1)
|
||||
break;
|
||||
next = start + offset;
|
||||
|
||||
memcpy(result_s, start, next - start);
|
||||
|
||||
result_s += (next - start);
|
||||
start = next + from_len;
|
||||
}
|
||||
memcpy(result_s, start, end - start);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* len(self)>=1, len(from)==len(to)==1, maxcount>=1 */
|
||||
static PyObject *
|
||||
stringlib_replace_single_character_in_place(PyObject *self,
|
||||
char from_c, char to_c,
|
||||
Py_ssize_t maxcount)
|
||||
{
|
||||
const char *self_s, *end;
|
||||
char *result_s, *start, *next;
|
||||
Py_ssize_t self_len;
|
||||
PyObject *result;
|
||||
|
||||
/* The result string will be the same size */
|
||||
self_s = STRINGLIB_STR(self);
|
||||
self_len = STRINGLIB_LEN(self);
|
||||
|
||||
next = findchar(self_s, self_len, from_c);
|
||||
|
||||
if (next == NULL) {
|
||||
/* No matches; return the original bytes */
|
||||
return return_self(self);
|
||||
}
|
||||
|
||||
/* Need to make a new bytes */
|
||||
result = STRINGLIB_NEW(NULL, self_len);
|
||||
if (result == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
result_s = STRINGLIB_STR(result);
|
||||
memcpy(result_s, self_s, self_len);
|
||||
|
||||
/* change everything in-place, starting with this one */
|
||||
start = result_s + (next - self_s);
|
||||
*start = to_c;
|
||||
start++;
|
||||
end = result_s + self_len;
|
||||
|
||||
while (--maxcount > 0) {
|
||||
next = findchar(start, end - start, from_c);
|
||||
if (next == NULL)
|
||||
break;
|
||||
*next = to_c;
|
||||
start = next + 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* len(self)>=1, len(from)==len(to)>=2, maxcount>=1 */
|
||||
static PyObject *
|
||||
stringlib_replace_substring_in_place(PyObject *self,
|
||||
const char *from_s, Py_ssize_t from_len,
|
||||
const char *to_s, Py_ssize_t to_len,
|
||||
Py_ssize_t maxcount)
|
||||
{
|
||||
const char *self_s, *end;
|
||||
char *result_s, *start;
|
||||
Py_ssize_t self_len, offset;
|
||||
PyObject *result;
|
||||
|
||||
/* The result bytes will be the same size */
|
||||
|
||||
self_s = STRINGLIB_STR(self);
|
||||
self_len = STRINGLIB_LEN(self);
|
||||
|
||||
offset = stringlib_find(self_s, self_len,
|
||||
from_s, from_len,
|
||||
0);
|
||||
if (offset == -1) {
|
||||
/* No matches; return the original bytes */
|
||||
return return_self(self);
|
||||
}
|
||||
|
||||
/* Need to make a new bytes */
|
||||
result = STRINGLIB_NEW(NULL, self_len);
|
||||
if (result == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
result_s = STRINGLIB_STR(result);
|
||||
memcpy(result_s, self_s, self_len);
|
||||
|
||||
/* change everything in-place, starting with this one */
|
||||
start = result_s + offset;
|
||||
memcpy(start, to_s, from_len);
|
||||
start += from_len;
|
||||
end = result_s + self_len;
|
||||
|
||||
while ( --maxcount > 0) {
|
||||
offset = stringlib_find(start, end - start,
|
||||
from_s, from_len,
|
||||
0);
|
||||
if (offset == -1)
|
||||
break;
|
||||
memcpy(start + offset, to_s, from_len);
|
||||
start += offset + from_len;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* len(self)>=1, len(from)==1, len(to)>=2, maxcount>=1 */
|
||||
static PyObject *
|
||||
stringlib_replace_single_character(PyObject *self,
|
||||
char from_c,
|
||||
const char *to_s, Py_ssize_t to_len,
|
||||
Py_ssize_t maxcount)
|
||||
{
|
||||
const char *self_s, *start, *next, *end;
|
||||
char *result_s;
|
||||
Py_ssize_t self_len, result_len;
|
||||
Py_ssize_t count;
|
||||
PyObject *result;
|
||||
|
||||
self_s = STRINGLIB_STR(self);
|
||||
self_len = STRINGLIB_LEN(self);
|
||||
|
||||
count = countchar(self_s, self_len, from_c, maxcount);
|
||||
if (count == 0) {
|
||||
/* no matches, return unchanged */
|
||||
return return_self(self);
|
||||
}
|
||||
|
||||
/* use the difference between current and new, hence the "-1" */
|
||||
/* result_len = self_len + count * (to_len-1) */
|
||||
assert(count > 0);
|
||||
if (to_len - 1 > (PY_SSIZE_T_MAX - self_len) / count) {
|
||||
PyErr_SetString(PyExc_OverflowError, "replace bytes is too long");
|
||||
return NULL;
|
||||
}
|
||||
result_len = self_len + count * (to_len - 1);
|
||||
|
||||
result = STRINGLIB_NEW(NULL, result_len);
|
||||
if (result == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
result_s = STRINGLIB_STR(result);
|
||||
|
||||
start = self_s;
|
||||
end = self_s + self_len;
|
||||
while (count-- > 0) {
|
||||
next = findchar(start, end - start, from_c);
|
||||
if (next == NULL)
|
||||
break;
|
||||
|
||||
if (next == start) {
|
||||
/* replace with the 'to' */
|
||||
memcpy(result_s, to_s, to_len);
|
||||
result_s += to_len;
|
||||
start += 1;
|
||||
} else {
|
||||
/* copy the unchanged old then the 'to' */
|
||||
memcpy(result_s, start, next - start);
|
||||
result_s += (next - start);
|
||||
memcpy(result_s, to_s, to_len);
|
||||
result_s += to_len;
|
||||
start = next + 1;
|
||||
}
|
||||
}
|
||||
/* Copy the remainder of the remaining bytes */
|
||||
memcpy(result_s, start, end - start);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* len(self)>=1, len(from)>=2, len(to)>=2, maxcount>=1 */
|
||||
static PyObject *
|
||||
stringlib_replace_substring(PyObject *self,
|
||||
const char *from_s, Py_ssize_t from_len,
|
||||
const char *to_s, Py_ssize_t to_len,
|
||||
Py_ssize_t maxcount)
|
||||
{
|
||||
const char *self_s, *start, *next, *end;
|
||||
char *result_s;
|
||||
Py_ssize_t self_len, result_len;
|
||||
Py_ssize_t count, offset;
|
||||
PyObject *result;
|
||||
|
||||
self_s = STRINGLIB_STR(self);
|
||||
self_len = STRINGLIB_LEN(self);
|
||||
|
||||
count = stringlib_count(self_s, self_len,
|
||||
from_s, from_len,
|
||||
maxcount);
|
||||
|
||||
if (count == 0) {
|
||||
/* no matches, return unchanged */
|
||||
return return_self(self);
|
||||
}
|
||||
|
||||
/* Check for overflow */
|
||||
/* result_len = self_len + count * (to_len-from_len) */
|
||||
assert(count > 0);
|
||||
if (to_len - from_len > (PY_SSIZE_T_MAX - self_len) / count) {
|
||||
PyErr_SetString(PyExc_OverflowError, "replace bytes is too long");
|
||||
return NULL;
|
||||
}
|
||||
result_len = self_len + count * (to_len - from_len);
|
||||
|
||||
result = STRINGLIB_NEW(NULL, result_len);
|
||||
if (result == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
result_s = STRINGLIB_STR(result);
|
||||
|
||||
start = self_s;
|
||||
end = self_s + self_len;
|
||||
while (count-- > 0) {
|
||||
offset = stringlib_find(start, end - start,
|
||||
from_s, from_len,
|
||||
0);
|
||||
if (offset == -1)
|
||||
break;
|
||||
next = start + offset;
|
||||
if (next == start) {
|
||||
/* replace with the 'to' */
|
||||
memcpy(result_s, to_s, to_len);
|
||||
result_s += to_len;
|
||||
start += from_len;
|
||||
} else {
|
||||
/* copy the unchanged old then the 'to' */
|
||||
memcpy(result_s, start, next - start);
|
||||
result_s += (next - start);
|
||||
memcpy(result_s, to_s, to_len);
|
||||
result_s += to_len;
|
||||
start = next + from_len;
|
||||
}
|
||||
}
|
||||
/* Copy the remainder of the remaining bytes */
|
||||
memcpy(result_s, start, end - start);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
stringlib_replace(PyObject *self,
|
||||
const char *from_s, Py_ssize_t from_len,
|
||||
const char *to_s, Py_ssize_t to_len,
|
||||
Py_ssize_t maxcount)
|
||||
{
|
||||
if (maxcount < 0) {
|
||||
maxcount = PY_SSIZE_T_MAX;
|
||||
} else if (maxcount == 0 || STRINGLIB_LEN(self) == 0) {
|
||||
/* nothing to do; return the original bytes */
|
||||
return return_self(self);
|
||||
}
|
||||
|
||||
/* Handle zero-length special cases */
|
||||
if (from_len == 0) {
|
||||
if (to_len == 0) {
|
||||
/* nothing to do; return the original bytes */
|
||||
return return_self(self);
|
||||
}
|
||||
/* insert the 'to' bytes everywhere. */
|
||||
/* >>> b"Python".replace(b"", b".") */
|
||||
/* b'.P.y.t.h.o.n.' */
|
||||
return stringlib_replace_interleave(self, to_s, to_len, maxcount);
|
||||
}
|
||||
|
||||
/* Except for b"".replace(b"", b"A") == b"A" there is no way beyond this */
|
||||
/* point for an empty self bytes to generate a non-empty bytes */
|
||||
/* Special case so the remaining code always gets a non-empty bytes */
|
||||
if (STRINGLIB_LEN(self) == 0) {
|
||||
return return_self(self);
|
||||
}
|
||||
|
||||
if (to_len == 0) {
|
||||
/* delete all occurrences of 'from' bytes */
|
||||
if (from_len == 1) {
|
||||
return stringlib_replace_delete_single_character(
|
||||
self, from_s[0], maxcount);
|
||||
} else {
|
||||
return stringlib_replace_delete_substring(
|
||||
self, from_s, from_len, maxcount);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle special case where both bytes have the same length */
|
||||
|
||||
if (from_len == to_len) {
|
||||
if (from_len == 1) {
|
||||
return stringlib_replace_single_character_in_place(
|
||||
self, from_s[0], to_s[0], maxcount);
|
||||
} else {
|
||||
return stringlib_replace_substring_in_place(
|
||||
self, from_s, from_len, to_s, to_len, maxcount);
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise use the more generic algorithms */
|
||||
if (from_len == 1) {
|
||||
return stringlib_replace_single_character(
|
||||
self, from_s[0], to_s, to_len, maxcount);
|
||||
} else {
|
||||
/* len('from')>=2, len('to')>=1 */
|
||||
return stringlib_replace_substring(
|
||||
self, from_s, from_len, to_s, to_len, maxcount);
|
||||
}
|
||||
}
|
||||
|
||||
#undef findchar
|
30
third_party/python/Objects/stringlib/ucs1lib.h
vendored
Normal file
30
third_party/python/Objects/stringlib/ucs1lib.h
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* this is sort of a hack. there's at least one place (formatting
|
||||
floats) where some stringlib code takes a different path if it's
|
||||
compiled as unicode. */
|
||||
#define STRINGLIB_IS_UNICODE 1
|
||||
|
||||
#define FASTSEARCH ucs1lib_fastsearch
|
||||
#define STRINGLIB(F) ucs1lib_##F
|
||||
#define STRINGLIB_OBJECT PyUnicodeObject
|
||||
#define STRINGLIB_SIZEOF_CHAR 1
|
||||
#define STRINGLIB_MAX_CHAR 0xFFu
|
||||
#define STRINGLIB_CHAR Py_UCS1
|
||||
#define STRINGLIB_TYPE_NAME "unicode"
|
||||
#define STRINGLIB_PARSE_CODE "U"
|
||||
#define STRINGLIB_EMPTY unicode_empty
|
||||
#define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE
|
||||
#define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK
|
||||
#define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL
|
||||
#define STRINGLIB_TODECIMAL Py_UNICODE_TODECIMAL
|
||||
#define STRINGLIB_STR PyUnicode_1BYTE_DATA
|
||||
#define STRINGLIB_LEN PyUnicode_GET_LENGTH
|
||||
#define STRINGLIB_NEW _PyUnicode_FromUCS1
|
||||
#define STRINGLIB_CHECK PyUnicode_Check
|
||||
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
|
||||
|
||||
#define STRINGLIB_TOSTR PyObject_Str
|
||||
#define STRINGLIB_TOASCII PyObject_ASCII
|
||||
|
||||
#define _Py_InsertThousandsGrouping _PyUnicode_ucs1_InsertThousandsGrouping
|
||||
|
||||
|
29
third_party/python/Objects/stringlib/ucs2lib.h
vendored
Normal file
29
third_party/python/Objects/stringlib/ucs2lib.h
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* this is sort of a hack. there's at least one place (formatting
|
||||
floats) where some stringlib code takes a different path if it's
|
||||
compiled as unicode. */
|
||||
#define STRINGLIB_IS_UNICODE 1
|
||||
|
||||
#define FASTSEARCH ucs2lib_fastsearch
|
||||
#define STRINGLIB(F) ucs2lib_##F
|
||||
#define STRINGLIB_OBJECT PyUnicodeObject
|
||||
#define STRINGLIB_SIZEOF_CHAR 2
|
||||
#define STRINGLIB_MAX_CHAR 0xFFFFu
|
||||
#define STRINGLIB_CHAR Py_UCS2
|
||||
#define STRINGLIB_TYPE_NAME "unicode"
|
||||
#define STRINGLIB_PARSE_CODE "U"
|
||||
#define STRINGLIB_EMPTY unicode_empty
|
||||
#define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE
|
||||
#define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK
|
||||
#define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL
|
||||
#define STRINGLIB_TODECIMAL Py_UNICODE_TODECIMAL
|
||||
#define STRINGLIB_STR PyUnicode_2BYTE_DATA
|
||||
#define STRINGLIB_LEN PyUnicode_GET_LENGTH
|
||||
#define STRINGLIB_NEW _PyUnicode_FromUCS2
|
||||
#define STRINGLIB_CHECK PyUnicode_Check
|
||||
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
|
||||
|
||||
#define STRINGLIB_TOSTR PyObject_Str
|
||||
#define STRINGLIB_TOASCII PyObject_ASCII
|
||||
|
||||
#define _Py_InsertThousandsGrouping _PyUnicode_ucs2_InsertThousandsGrouping
|
||||
|
29
third_party/python/Objects/stringlib/ucs4lib.h
vendored
Normal file
29
third_party/python/Objects/stringlib/ucs4lib.h
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* this is sort of a hack. there's at least one place (formatting
|
||||
floats) where some stringlib code takes a different path if it's
|
||||
compiled as unicode. */
|
||||
#define STRINGLIB_IS_UNICODE 1
|
||||
|
||||
#define FASTSEARCH ucs4lib_fastsearch
|
||||
#define STRINGLIB(F) ucs4lib_##F
|
||||
#define STRINGLIB_OBJECT PyUnicodeObject
|
||||
#define STRINGLIB_SIZEOF_CHAR 4
|
||||
#define STRINGLIB_MAX_CHAR 0x10FFFFu
|
||||
#define STRINGLIB_CHAR Py_UCS4
|
||||
#define STRINGLIB_TYPE_NAME "unicode"
|
||||
#define STRINGLIB_PARSE_CODE "U"
|
||||
#define STRINGLIB_EMPTY unicode_empty
|
||||
#define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE
|
||||
#define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK
|
||||
#define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL
|
||||
#define STRINGLIB_TODECIMAL Py_UNICODE_TODECIMAL
|
||||
#define STRINGLIB_STR PyUnicode_4BYTE_DATA
|
||||
#define STRINGLIB_LEN PyUnicode_GET_LENGTH
|
||||
#define STRINGLIB_NEW _PyUnicode_FromUCS4
|
||||
#define STRINGLIB_CHECK PyUnicode_Check
|
||||
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
|
||||
|
||||
#define STRINGLIB_TOSTR PyObject_Str
|
||||
#define STRINGLIB_TOASCII PyObject_ASCII
|
||||
|
||||
#define _Py_InsertThousandsGrouping _PyUnicode_ucs4_InsertThousandsGrouping
|
||||
|
11
third_party/python/Objects/stringlib/undef.h
vendored
Normal file
11
third_party/python/Objects/stringlib/undef.h
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
#undef FASTSEARCH
|
||||
#undef STRINGLIB
|
||||
#undef STRINGLIB_SIZEOF_CHAR
|
||||
#undef STRINGLIB_MAX_CHAR
|
||||
#undef STRINGLIB_CHAR
|
||||
#undef STRINGLIB_STR
|
||||
#undef STRINGLIB_LEN
|
||||
#undef STRINGLIB_NEW
|
||||
#undef _Py_InsertThousandsGrouping
|
||||
#undef STRINGLIB_IS_UNICODE
|
||||
|
1288
third_party/python/Objects/stringlib/unicode_format.h
vendored
Normal file
1288
third_party/python/Objects/stringlib/unicode_format.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
32
third_party/python/Objects/stringlib/unicodedefs.h
vendored
Normal file
32
third_party/python/Objects/stringlib/unicodedefs.h
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef STRINGLIB_UNICODEDEFS_H
|
||||
#define STRINGLIB_UNICODEDEFS_H
|
||||
|
||||
/* this is sort of a hack. there's at least one place (formatting
|
||||
floats) where some stringlib code takes a different path if it's
|
||||
compiled as unicode. */
|
||||
#define STRINGLIB_IS_UNICODE 1
|
||||
|
||||
#define FASTSEARCH fastsearch
|
||||
#define STRINGLIB(F) stringlib_##F
|
||||
#define STRINGLIB_OBJECT PyUnicodeObject
|
||||
#define STRINGLIB_SIZEOF_CHAR Py_UNICODE_SIZE
|
||||
#define STRINGLIB_CHAR Py_UNICODE
|
||||
#define STRINGLIB_TYPE_NAME "unicode"
|
||||
#define STRINGLIB_PARSE_CODE "U"
|
||||
#define STRINGLIB_EMPTY unicode_empty
|
||||
#define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE
|
||||
#define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK
|
||||
#define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL
|
||||
#define STRINGLIB_TODECIMAL Py_UNICODE_TODECIMAL
|
||||
#define STRINGLIB_STR PyUnicode_AS_UNICODE
|
||||
#define STRINGLIB_LEN PyUnicode_GET_SIZE
|
||||
#define STRINGLIB_NEW PyUnicode_FromUnicode
|
||||
#define STRINGLIB_CHECK PyUnicode_Check
|
||||
#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact
|
||||
|
||||
#define STRINGLIB_TOSTR PyObject_Str
|
||||
#define STRINGLIB_TOASCII PyObject_ASCII
|
||||
|
||||
#define STRINGLIB_WANT_CONTAINS_OBJ 1
|
||||
|
||||
#endif /* !STRINGLIB_UNICODEDEFS_H */
|
424
third_party/python/Objects/structseq.c
vendored
Normal file
424
third_party/python/Objects/structseq.c
vendored
Normal file
|
@ -0,0 +1,424 @@
|
|||
/* Implementation helper: a struct that looks like a tuple. See timemodule
|
||||
and posixmodule for example uses. */
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
|
||||
static const char visible_length_key[] = "n_sequence_fields";
|
||||
static const char real_length_key[] = "n_fields";
|
||||
static const char unnamed_fields_key[] = "n_unnamed_fields";
|
||||
|
||||
/* Fields with this name have only a field index, not a field name.
|
||||
They are only allowed for indices < n_visible_fields. */
|
||||
char *PyStructSequence_UnnamedField = "unnamed field";
|
||||
_Py_IDENTIFIER(n_sequence_fields);
|
||||
_Py_IDENTIFIER(n_fields);
|
||||
_Py_IDENTIFIER(n_unnamed_fields);
|
||||
|
||||
#define VISIBLE_SIZE(op) Py_SIZE(op)
|
||||
#define VISIBLE_SIZE_TP(tp) PyLong_AsSsize_t( \
|
||||
_PyDict_GetItemId((tp)->tp_dict, &PyId_n_sequence_fields))
|
||||
|
||||
#define REAL_SIZE_TP(tp) PyLong_AsSsize_t( \
|
||||
_PyDict_GetItemId((tp)->tp_dict, &PyId_n_fields))
|
||||
#define REAL_SIZE(op) REAL_SIZE_TP(Py_TYPE(op))
|
||||
|
||||
#define UNNAMED_FIELDS_TP(tp) PyLong_AsSsize_t( \
|
||||
_PyDict_GetItemId((tp)->tp_dict, &PyId_n_unnamed_fields))
|
||||
#define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op))
|
||||
|
||||
|
||||
PyObject *
|
||||
PyStructSequence_New(PyTypeObject *type)
|
||||
{
|
||||
PyStructSequence *obj;
|
||||
Py_ssize_t size = REAL_SIZE_TP(type), i;
|
||||
|
||||
obj = PyObject_GC_NewVar(PyStructSequence, type, size);
|
||||
if (obj == NULL)
|
||||
return NULL;
|
||||
/* Hack the size of the variable object, so invisible fields don't appear
|
||||
to Python code. */
|
||||
Py_SIZE(obj) = VISIBLE_SIZE_TP(type);
|
||||
for (i = 0; i < size; i++)
|
||||
obj->ob_item[i] = NULL;
|
||||
|
||||
return (PyObject*)obj;
|
||||
}
|
||||
|
||||
void
|
||||
PyStructSequence_SetItem(PyObject* op, Py_ssize_t i, PyObject* v)
|
||||
{
|
||||
PyStructSequence_SET_ITEM(op, i, v);
|
||||
}
|
||||
|
||||
PyObject*
|
||||
PyStructSequence_GetItem(PyObject* op, Py_ssize_t i)
|
||||
{
|
||||
return PyStructSequence_GET_ITEM(op, i);
|
||||
}
|
||||
|
||||
static void
|
||||
structseq_dealloc(PyStructSequence *obj)
|
||||
{
|
||||
Py_ssize_t i, size;
|
||||
|
||||
size = REAL_SIZE(obj);
|
||||
for (i = 0; i < size; ++i) {
|
||||
Py_XDECREF(obj->ob_item[i]);
|
||||
}
|
||||
PyObject_GC_Del(obj);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *arg = NULL;
|
||||
PyObject *dict = NULL;
|
||||
PyObject *ob;
|
||||
PyStructSequence *res = NULL;
|
||||
Py_ssize_t len, min_len, max_len, i, n_unnamed_fields;
|
||||
static char *kwlist[] = {"sequence", "dict", 0};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq",
|
||||
kwlist, &arg, &dict))
|
||||
return NULL;
|
||||
|
||||
arg = PySequence_Fast(arg, "constructor requires a sequence");
|
||||
|
||||
if (!arg) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dict && !PyDict_Check(dict)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.500s() takes a dict as second arg, if any",
|
||||
type->tp_name);
|
||||
Py_DECREF(arg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = PySequence_Fast_GET_SIZE(arg);
|
||||
min_len = VISIBLE_SIZE_TP(type);
|
||||
max_len = REAL_SIZE_TP(type);
|
||||
n_unnamed_fields = UNNAMED_FIELDS_TP(type);
|
||||
|
||||
if (min_len != max_len) {
|
||||
if (len < min_len) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.500s() takes an at least %zd-sequence (%zd-sequence given)",
|
||||
type->tp_name, min_len, len);
|
||||
Py_DECREF(arg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (len > max_len) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.500s() takes an at most %zd-sequence (%zd-sequence given)",
|
||||
type->tp_name, max_len, len);
|
||||
Py_DECREF(arg);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (len != min_len) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.500s() takes a %zd-sequence (%zd-sequence given)",
|
||||
type->tp_name, min_len, len);
|
||||
Py_DECREF(arg);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
res = (PyStructSequence*) PyStructSequence_New(type);
|
||||
if (res == NULL) {
|
||||
Py_DECREF(arg);
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < len; ++i) {
|
||||
PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
|
||||
Py_INCREF(v);
|
||||
res->ob_item[i] = v;
|
||||
}
|
||||
for (; i < max_len; ++i) {
|
||||
if (dict && (ob = PyDict_GetItemString(
|
||||
dict, type->tp_members[i-n_unnamed_fields].name))) {
|
||||
}
|
||||
else {
|
||||
ob = Py_None;
|
||||
}
|
||||
Py_INCREF(ob);
|
||||
res->ob_item[i] = ob;
|
||||
}
|
||||
|
||||
Py_DECREF(arg);
|
||||
return (PyObject*) res;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
structseq_repr(PyStructSequence *obj)
|
||||
{
|
||||
/* buffer and type size were chosen well considered. */
|
||||
#define REPR_BUFFER_SIZE 512
|
||||
#define TYPE_MAXSIZE 100
|
||||
|
||||
PyTypeObject *typ = Py_TYPE(obj);
|
||||
Py_ssize_t i;
|
||||
int removelast = 0;
|
||||
Py_ssize_t len;
|
||||
char buf[REPR_BUFFER_SIZE];
|
||||
char *endofbuf, *pbuf = buf;
|
||||
|
||||
/* pointer to end of writeable buffer; safes space for "...)\0" */
|
||||
endofbuf= &buf[REPR_BUFFER_SIZE-5];
|
||||
|
||||
/* "typename(", limited to TYPE_MAXSIZE */
|
||||
len = strlen(typ->tp_name) > TYPE_MAXSIZE ? TYPE_MAXSIZE :
|
||||
strlen(typ->tp_name);
|
||||
strncpy(pbuf, typ->tp_name, len);
|
||||
pbuf += len;
|
||||
*pbuf++ = '(';
|
||||
|
||||
for (i=0; i < VISIBLE_SIZE(obj); i++) {
|
||||
PyObject *val, *repr;
|
||||
char *cname, *crepr;
|
||||
|
||||
cname = typ->tp_members[i].name;
|
||||
if (cname == NULL) {
|
||||
PyErr_Format(PyExc_SystemError, "In structseq_repr(), member %d name is NULL"
|
||||
" for type %.500s", i, typ->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
val = PyStructSequence_GET_ITEM(obj, i);
|
||||
repr = PyObject_Repr(val);
|
||||
if (repr == NULL)
|
||||
return NULL;
|
||||
crepr = PyUnicode_AsUTF8(repr);
|
||||
if (crepr == NULL) {
|
||||
Py_DECREF(repr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* + 3: keep space for "=" and ", " */
|
||||
len = strlen(cname) + strlen(crepr) + 3;
|
||||
if ((pbuf+len) <= endofbuf) {
|
||||
strcpy(pbuf, cname);
|
||||
pbuf += strlen(cname);
|
||||
*pbuf++ = '=';
|
||||
strcpy(pbuf, crepr);
|
||||
pbuf += strlen(crepr);
|
||||
*pbuf++ = ',';
|
||||
*pbuf++ = ' ';
|
||||
removelast = 1;
|
||||
Py_DECREF(repr);
|
||||
}
|
||||
else {
|
||||
strcpy(pbuf, "...");
|
||||
pbuf += 3;
|
||||
removelast = 0;
|
||||
Py_DECREF(repr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (removelast) {
|
||||
/* overwrite last ", " */
|
||||
pbuf-=2;
|
||||
}
|
||||
*pbuf++ = ')';
|
||||
*pbuf = '\0';
|
||||
|
||||
return PyUnicode_FromString(buf);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
structseq_reduce(PyStructSequence* self)
|
||||
{
|
||||
PyObject* tup = NULL;
|
||||
PyObject* dict = NULL;
|
||||
PyObject* result;
|
||||
Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields, i;
|
||||
|
||||
n_fields = REAL_SIZE(self);
|
||||
n_visible_fields = VISIBLE_SIZE(self);
|
||||
n_unnamed_fields = UNNAMED_FIELDS(self);
|
||||
tup = PyTuple_New(n_visible_fields);
|
||||
if (!tup)
|
||||
goto error;
|
||||
|
||||
dict = PyDict_New();
|
||||
if (!dict)
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < n_visible_fields; i++) {
|
||||
Py_INCREF(self->ob_item[i]);
|
||||
PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
|
||||
}
|
||||
|
||||
for (; i < n_fields; i++) {
|
||||
char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name;
|
||||
if (PyDict_SetItemString(dict, n, self->ob_item[i]) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict);
|
||||
|
||||
Py_DECREF(tup);
|
||||
Py_DECREF(dict);
|
||||
|
||||
return result;
|
||||
|
||||
error:
|
||||
Py_XDECREF(tup);
|
||||
Py_XDECREF(dict);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyMethodDef structseq_methods[] = {
|
||||
{"__reduce__", (PyCFunction)structseq_reduce, METH_NOARGS, NULL},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static PyTypeObject _struct_sequence_template = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
NULL, /* tp_name */
|
||||
sizeof(PyStructSequence) - sizeof(PyObject *), /* tp_basicsize */
|
||||
sizeof(PyObject *), /* tp_itemsize */
|
||||
(destructor)structseq_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
(reprfunc)structseq_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
NULL, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
structseq_methods, /* tp_methods */
|
||||
NULL, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
structseq_new, /* tp_new */
|
||||
};
|
||||
|
||||
int
|
||||
PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
|
||||
{
|
||||
PyObject *dict;
|
||||
PyMemberDef* members;
|
||||
Py_ssize_t n_members, n_unnamed_members, i, k;
|
||||
PyObject *v;
|
||||
|
||||
#ifdef Py_TRACE_REFS
|
||||
/* if the type object was chained, unchain it first
|
||||
before overwriting its storage */
|
||||
if (type->ob_base.ob_base._ob_next) {
|
||||
_Py_ForgetReference((PyObject*)type);
|
||||
}
|
||||
#endif
|
||||
|
||||
n_unnamed_members = 0;
|
||||
for (i = 0; desc->fields[i].name != NULL; ++i)
|
||||
if (desc->fields[i].name == PyStructSequence_UnnamedField)
|
||||
n_unnamed_members++;
|
||||
n_members = i;
|
||||
|
||||
memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
|
||||
type->tp_base = &PyTuple_Type;
|
||||
type->tp_name = desc->name;
|
||||
type->tp_doc = desc->doc;
|
||||
|
||||
members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);
|
||||
if (members == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = k = 0; i < n_members; ++i) {
|
||||
if (desc->fields[i].name == PyStructSequence_UnnamedField)
|
||||
continue;
|
||||
members[k].name = desc->fields[i].name;
|
||||
members[k].type = T_OBJECT;
|
||||
members[k].offset = offsetof(PyStructSequence, ob_item)
|
||||
+ i * sizeof(PyObject*);
|
||||
members[k].flags = READONLY;
|
||||
members[k].doc = desc->fields[i].doc;
|
||||
k++;
|
||||
}
|
||||
members[k].name = NULL;
|
||||
|
||||
type->tp_members = members;
|
||||
|
||||
if (PyType_Ready(type) < 0)
|
||||
return -1;
|
||||
Py_INCREF(type);
|
||||
|
||||
dict = type->tp_dict;
|
||||
#define SET_DICT_FROM_SIZE(key, value) \
|
||||
do { \
|
||||
v = PyLong_FromSsize_t(value); \
|
||||
if (v == NULL) \
|
||||
return -1; \
|
||||
if (PyDict_SetItemString(dict, key, v) < 0) { \
|
||||
Py_DECREF(v); \
|
||||
return -1; \
|
||||
} \
|
||||
Py_DECREF(v); \
|
||||
} while (0)
|
||||
|
||||
SET_DICT_FROM_SIZE(visible_length_key, desc->n_in_sequence);
|
||||
SET_DICT_FROM_SIZE(real_length_key, n_members);
|
||||
SET_DICT_FROM_SIZE(unnamed_fields_key, n_unnamed_members);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
|
||||
{
|
||||
(void)PyStructSequence_InitType2(type, desc);
|
||||
}
|
||||
|
||||
PyTypeObject*
|
||||
PyStructSequence_NewType(PyStructSequence_Desc *desc)
|
||||
{
|
||||
PyTypeObject *result;
|
||||
|
||||
result = (PyTypeObject*)PyType_GenericAlloc(&PyType_Type, 0);
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
if (PyStructSequence_InitType2(result, desc) < 0) {
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int _PyStructSequence_Init(void)
|
||||
{
|
||||
if (_PyUnicode_FromId(&PyId_n_sequence_fields) == NULL
|
||||
|| _PyUnicode_FromId(&PyId_n_fields) == NULL
|
||||
|| _PyUnicode_FromId(&PyId_n_unnamed_fields) == NULL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
1073
third_party/python/Objects/tupleobject.c
vendored
Normal file
1073
third_party/python/Objects/tupleobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
7625
third_party/python/Objects/typeobject.c
vendored
Normal file
7625
third_party/python/Objects/typeobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
81
third_party/python/Objects/typeslots.inc
generated
vendored
Normal file
81
third_party/python/Objects/typeslots.inc
generated
vendored
Normal file
|
@ -0,0 +1,81 @@
|
|||
/* Generated by typeslots.py */
|
||||
0,
|
||||
0,
|
||||
offsetof(PyHeapTypeObject, as_mapping.mp_ass_subscript),
|
||||
offsetof(PyHeapTypeObject, as_mapping.mp_length),
|
||||
offsetof(PyHeapTypeObject, as_mapping.mp_subscript),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_absolute),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_add),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_and),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_bool),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_divmod),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_float),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_floor_divide),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_index),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_inplace_add),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_inplace_and),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_inplace_floor_divide),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_inplace_lshift),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_inplace_multiply),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_inplace_or),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_inplace_power),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_inplace_remainder),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_inplace_rshift),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_inplace_subtract),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_inplace_true_divide),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_inplace_xor),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_int),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_invert),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_lshift),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_multiply),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_negative),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_or),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_positive),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_power),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_remainder),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_rshift),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_subtract),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_true_divide),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_xor),
|
||||
offsetof(PyHeapTypeObject, as_sequence.sq_ass_item),
|
||||
offsetof(PyHeapTypeObject, as_sequence.sq_concat),
|
||||
offsetof(PyHeapTypeObject, as_sequence.sq_contains),
|
||||
offsetof(PyHeapTypeObject, as_sequence.sq_inplace_concat),
|
||||
offsetof(PyHeapTypeObject, as_sequence.sq_inplace_repeat),
|
||||
offsetof(PyHeapTypeObject, as_sequence.sq_item),
|
||||
offsetof(PyHeapTypeObject, as_sequence.sq_length),
|
||||
offsetof(PyHeapTypeObject, as_sequence.sq_repeat),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_alloc),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_base),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_bases),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_call),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_clear),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_dealloc),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_del),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_descr_get),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_descr_set),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_doc),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_getattr),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_getattro),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_hash),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_init),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_is_gc),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_iter),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_iternext),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_methods),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_new),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_repr),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_richcompare),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_setattr),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_setattro),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_str),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_traverse),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_members),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_getset),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_free),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_matrix_multiply),
|
||||
offsetof(PyHeapTypeObject, as_number.nb_inplace_matrix_multiply),
|
||||
offsetof(PyHeapTypeObject, as_async.am_await),
|
||||
offsetof(PyHeapTypeObject, as_async.am_aiter),
|
||||
offsetof(PyHeapTypeObject, as_async.am_anext),
|
||||
offsetof(PyHeapTypeObject, ht_type.tp_finalize),
|
43
third_party/python/Objects/typeslots.py
vendored
Executable file
43
third_party/python/Objects/typeslots.py
vendored
Executable file
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/python
|
||||
# Usage: typeslots.py < Include/typeslots.h typeslots.inc
|
||||
|
||||
import sys, re
|
||||
|
||||
def generate_typeslots(out=sys.stdout):
|
||||
out.write("/* Generated by typeslots.py */\n")
|
||||
res = {}
|
||||
for line in sys.stdin:
|
||||
m = re.match("#define Py_([a-z_]+) ([0-9]+)", line)
|
||||
if not m:
|
||||
continue
|
||||
member = m.group(1)
|
||||
if member.startswith("tp_"):
|
||||
member = "ht_type."+member
|
||||
elif member.startswith("am_"):
|
||||
member = "as_async."+member
|
||||
elif member.startswith("nb_"):
|
||||
member = "as_number."+member
|
||||
elif member.startswith("mp_"):
|
||||
member = "as_mapping."+member
|
||||
elif member.startswith("sq_"):
|
||||
member = "as_sequence."+member
|
||||
elif member.startswith("bf_"):
|
||||
member = "as_buffer."+member
|
||||
res[int(m.group(2))] = member
|
||||
|
||||
M = max(res.keys())+1
|
||||
for i in range(1,M):
|
||||
if i in res:
|
||||
out.write("offsetof(PyHeapTypeObject, %s),\n" % res[i])
|
||||
else:
|
||||
out.write("0,\n")
|
||||
|
||||
def main():
|
||||
if len(sys.argv) == 2:
|
||||
with open(sys.argv[1], "w") as f:
|
||||
generate_typeslots(f)
|
||||
else:
|
||||
generate_typeslots()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
297
third_party/python/Objects/unicodectype.c
vendored
Normal file
297
third_party/python/Objects/unicodectype.c
vendored
Normal file
|
@ -0,0 +1,297 @@
|
|||
/*
|
||||
Unicode character type helpers.
|
||||
|
||||
Written by Marc-Andre Lemburg (mal@lemburg.com).
|
||||
Modified for Python 2.0 by Fredrik Lundh (fredrik@pythonware.com)
|
||||
|
||||
Copyright (c) Corporation for National Research Initiatives.
|
||||
|
||||
*/
|
||||
|
||||
#include "Python.h"
|
||||
|
||||
#define ALPHA_MASK 0x01
|
||||
#define DECIMAL_MASK 0x02
|
||||
#define DIGIT_MASK 0x04
|
||||
#define LOWER_MASK 0x08
|
||||
#define LINEBREAK_MASK 0x10
|
||||
#define SPACE_MASK 0x20
|
||||
#define TITLE_MASK 0x40
|
||||
#define UPPER_MASK 0x80
|
||||
#define XID_START_MASK 0x100
|
||||
#define XID_CONTINUE_MASK 0x200
|
||||
#define PRINTABLE_MASK 0x400
|
||||
#define NUMERIC_MASK 0x800
|
||||
#define CASE_IGNORABLE_MASK 0x1000
|
||||
#define CASED_MASK 0x2000
|
||||
#define EXTENDED_CASE_MASK 0x4000
|
||||
|
||||
typedef struct {
|
||||
/*
|
||||
These are either deltas to the character or offsets in
|
||||
_PyUnicode_ExtendedCase.
|
||||
*/
|
||||
const int upper;
|
||||
const int lower;
|
||||
const int title;
|
||||
/* Note if more flag space is needed, decimal and digit could be unified. */
|
||||
const unsigned char decimal;
|
||||
const unsigned char digit;
|
||||
const unsigned short flags;
|
||||
} _PyUnicode_TypeRecord;
|
||||
|
||||
#include "unicodetype_db.h"
|
||||
|
||||
static const _PyUnicode_TypeRecord *
|
||||
gettyperecord(Py_UCS4 code)
|
||||
{
|
||||
int index;
|
||||
|
||||
if (code >= 0x110000)
|
||||
index = 0;
|
||||
else
|
||||
{
|
||||
index = index1[(code>>SHIFT)];
|
||||
index = index2[(index<<SHIFT)+(code&((1<<SHIFT)-1))];
|
||||
}
|
||||
|
||||
return &_PyUnicode_TypeRecords[index];
|
||||
}
|
||||
|
||||
/* Returns the titlecase Unicode characters corresponding to ch or just
|
||||
ch if no titlecase mapping is known. */
|
||||
|
||||
Py_UCS4 _PyUnicode_ToTitlecase(Py_UCS4 ch)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
if (ctype->flags & EXTENDED_CASE_MASK)
|
||||
return _PyUnicode_ExtendedCase[ctype->title & 0xFFFF];
|
||||
return ch + ctype->title;
|
||||
}
|
||||
|
||||
/* Returns 1 for Unicode characters having the category 'Lt', 0
|
||||
otherwise. */
|
||||
|
||||
int _PyUnicode_IsTitlecase(Py_UCS4 ch)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
return (ctype->flags & TITLE_MASK) != 0;
|
||||
}
|
||||
|
||||
/* Returns 1 for Unicode characters having the XID_Start property, 0
|
||||
otherwise. */
|
||||
|
||||
int _PyUnicode_IsXidStart(Py_UCS4 ch)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
return (ctype->flags & XID_START_MASK) != 0;
|
||||
}
|
||||
|
||||
/* Returns 1 for Unicode characters having the XID_Continue property,
|
||||
0 otherwise. */
|
||||
|
||||
int _PyUnicode_IsXidContinue(Py_UCS4 ch)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
return (ctype->flags & XID_CONTINUE_MASK) != 0;
|
||||
}
|
||||
|
||||
/* Returns the integer decimal (0-9) for Unicode characters having
|
||||
this property, -1 otherwise. */
|
||||
|
||||
int _PyUnicode_ToDecimalDigit(Py_UCS4 ch)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
return (ctype->flags & DECIMAL_MASK) ? ctype->decimal : -1;
|
||||
}
|
||||
|
||||
int _PyUnicode_IsDecimalDigit(Py_UCS4 ch)
|
||||
{
|
||||
if (_PyUnicode_ToDecimalDigit(ch) < 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Returns the integer digit (0-9) for Unicode characters having
|
||||
this property, -1 otherwise. */
|
||||
|
||||
int _PyUnicode_ToDigit(Py_UCS4 ch)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
return (ctype->flags & DIGIT_MASK) ? ctype->digit : -1;
|
||||
}
|
||||
|
||||
int _PyUnicode_IsDigit(Py_UCS4 ch)
|
||||
{
|
||||
if (_PyUnicode_ToDigit(ch) < 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Returns the numeric value as double for Unicode characters having
|
||||
this property, -1.0 otherwise. */
|
||||
|
||||
int _PyUnicode_IsNumeric(Py_UCS4 ch)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
return (ctype->flags & NUMERIC_MASK) != 0;
|
||||
}
|
||||
|
||||
/* Returns 1 for Unicode characters to be hex-escaped when repr()ed,
|
||||
0 otherwise.
|
||||
All characters except those characters defined in the Unicode character
|
||||
database as following categories are considered printable.
|
||||
* Cc (Other, Control)
|
||||
* Cf (Other, Format)
|
||||
* Cs (Other, Surrogate)
|
||||
* Co (Other, Private Use)
|
||||
* Cn (Other, Not Assigned)
|
||||
* Zl Separator, Line ('\u2028', LINE SEPARATOR)
|
||||
* Zp Separator, Paragraph ('\u2029', PARAGRAPH SEPARATOR)
|
||||
* Zs (Separator, Space) other than ASCII space('\x20').
|
||||
*/
|
||||
int _PyUnicode_IsPrintable(Py_UCS4 ch)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
return (ctype->flags & PRINTABLE_MASK) != 0;
|
||||
}
|
||||
|
||||
/* Returns 1 for Unicode characters having the category 'Ll', 0
|
||||
otherwise. */
|
||||
|
||||
int _PyUnicode_IsLowercase(Py_UCS4 ch)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
return (ctype->flags & LOWER_MASK) != 0;
|
||||
}
|
||||
|
||||
/* Returns 1 for Unicode characters having the category 'Lu', 0
|
||||
otherwise. */
|
||||
|
||||
int _PyUnicode_IsUppercase(Py_UCS4 ch)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
return (ctype->flags & UPPER_MASK) != 0;
|
||||
}
|
||||
|
||||
/* Returns the uppercase Unicode characters corresponding to ch or just
|
||||
ch if no uppercase mapping is known. */
|
||||
|
||||
Py_UCS4 _PyUnicode_ToUppercase(Py_UCS4 ch)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
if (ctype->flags & EXTENDED_CASE_MASK)
|
||||
return _PyUnicode_ExtendedCase[ctype->upper & 0xFFFF];
|
||||
return ch + ctype->upper;
|
||||
}
|
||||
|
||||
/* Returns the lowercase Unicode characters corresponding to ch or just
|
||||
ch if no lowercase mapping is known. */
|
||||
|
||||
Py_UCS4 _PyUnicode_ToLowercase(Py_UCS4 ch)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
if (ctype->flags & EXTENDED_CASE_MASK)
|
||||
return _PyUnicode_ExtendedCase[ctype->lower & 0xFFFF];
|
||||
return ch + ctype->lower;
|
||||
}
|
||||
|
||||
int _PyUnicode_ToLowerFull(Py_UCS4 ch, Py_UCS4 *res)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
if (ctype->flags & EXTENDED_CASE_MASK) {
|
||||
int index = ctype->lower & 0xFFFF;
|
||||
int n = ctype->lower >> 24;
|
||||
int i;
|
||||
for (i = 0; i < n; i++)
|
||||
res[i] = _PyUnicode_ExtendedCase[index + i];
|
||||
return n;
|
||||
}
|
||||
res[0] = ch + ctype->lower;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _PyUnicode_ToTitleFull(Py_UCS4 ch, Py_UCS4 *res)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
if (ctype->flags & EXTENDED_CASE_MASK) {
|
||||
int index = ctype->title & 0xFFFF;
|
||||
int n = ctype->title >> 24;
|
||||
int i;
|
||||
for (i = 0; i < n; i++)
|
||||
res[i] = _PyUnicode_ExtendedCase[index + i];
|
||||
return n;
|
||||
}
|
||||
res[0] = ch + ctype->title;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _PyUnicode_ToUpperFull(Py_UCS4 ch, Py_UCS4 *res)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
if (ctype->flags & EXTENDED_CASE_MASK) {
|
||||
int index = ctype->upper & 0xFFFF;
|
||||
int n = ctype->upper >> 24;
|
||||
int i;
|
||||
for (i = 0; i < n; i++)
|
||||
res[i] = _PyUnicode_ExtendedCase[index + i];
|
||||
return n;
|
||||
}
|
||||
res[0] = ch + ctype->upper;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _PyUnicode_ToFoldedFull(Py_UCS4 ch, Py_UCS4 *res)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
if (ctype->flags & EXTENDED_CASE_MASK && (ctype->lower >> 20) & 7) {
|
||||
int index = (ctype->lower & 0xFFFF) + (ctype->lower >> 24);
|
||||
int n = (ctype->lower >> 20) & 7;
|
||||
int i;
|
||||
for (i = 0; i < n; i++)
|
||||
res[i] = _PyUnicode_ExtendedCase[index + i];
|
||||
return n;
|
||||
}
|
||||
return _PyUnicode_ToLowerFull(ch, res);
|
||||
}
|
||||
|
||||
int _PyUnicode_IsCased(Py_UCS4 ch)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
return (ctype->flags & CASED_MASK) != 0;
|
||||
}
|
||||
|
||||
int _PyUnicode_IsCaseIgnorable(Py_UCS4 ch)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
return (ctype->flags & CASE_IGNORABLE_MASK) != 0;
|
||||
}
|
||||
|
||||
/* Returns 1 for Unicode characters having the category 'Ll', 'Lu', 'Lt',
|
||||
'Lo' or 'Lm', 0 otherwise. */
|
||||
|
||||
int _PyUnicode_IsAlpha(Py_UCS4 ch)
|
||||
{
|
||||
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
|
||||
|
||||
return (ctype->flags & ALPHA_MASK) != 0;
|
||||
}
|
||||
|
15773
third_party/python/Objects/unicodeobject.c
vendored
Normal file
15773
third_party/python/Objects/unicodeobject.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
5799
third_party/python/Objects/unicodetype_db.h
vendored
Normal file
5799
third_party/python/Objects/unicodetype_db.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
961
third_party/python/Objects/weakrefobject.c
vendored
Normal file
961
third_party/python/Objects/weakrefobject.c
vendored
Normal file
|
@ -0,0 +1,961 @@
|
|||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
|
||||
|
||||
#define GET_WEAKREFS_LISTPTR(o) \
|
||||
((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
|
||||
|
||||
|
||||
Py_ssize_t
|
||||
_PyWeakref_GetWeakrefCount(PyWeakReference *head)
|
||||
{
|
||||
Py_ssize_t count = 0;
|
||||
|
||||
while (head != NULL) {
|
||||
++count;
|
||||
head = head->wr_next;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback)
|
||||
{
|
||||
self->hash = -1;
|
||||
self->wr_object = ob;
|
||||
self->wr_prev = NULL;
|
||||
self->wr_next = NULL;
|
||||
Py_XINCREF(callback);
|
||||
self->wr_callback = callback;
|
||||
}
|
||||
|
||||
static PyWeakReference *
|
||||
new_weakref(PyObject *ob, PyObject *callback)
|
||||
{
|
||||
PyWeakReference *result;
|
||||
|
||||
result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
|
||||
if (result) {
|
||||
init_weakref(result, ob, callback);
|
||||
PyObject_GC_Track(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* This function clears the passed-in reference and removes it from the
|
||||
* list of weak references for the referent. This is the only code that
|
||||
* removes an item from the doubly-linked list of weak references for an
|
||||
* object; it is also responsible for clearing the callback slot.
|
||||
*/
|
||||
static void
|
||||
clear_weakref(PyWeakReference *self)
|
||||
{
|
||||
PyObject *callback = self->wr_callback;
|
||||
|
||||
if (self->wr_object != Py_None) {
|
||||
PyWeakReference **list = GET_WEAKREFS_LISTPTR(self->wr_object);
|
||||
|
||||
if (*list == self)
|
||||
/* If 'self' is the end of the list (and thus self->wr_next == NULL)
|
||||
then the weakref list itself (and thus the value of *list) will
|
||||
end up being set to NULL. */
|
||||
*list = self->wr_next;
|
||||
self->wr_object = Py_None;
|
||||
if (self->wr_prev != NULL)
|
||||
self->wr_prev->wr_next = self->wr_next;
|
||||
if (self->wr_next != NULL)
|
||||
self->wr_next->wr_prev = self->wr_prev;
|
||||
self->wr_prev = NULL;
|
||||
self->wr_next = NULL;
|
||||
}
|
||||
if (callback != NULL) {
|
||||
Py_DECREF(callback);
|
||||
self->wr_callback = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cyclic gc uses this to *just* clear the passed-in reference, leaving
|
||||
* the callback intact and uncalled. It must be possible to call self's
|
||||
* tp_dealloc() after calling this, so self has to be left in a sane enough
|
||||
* state for that to work. We expect tp_dealloc to decref the callback
|
||||
* then. The reason for not letting clear_weakref() decref the callback
|
||||
* right now is that if the callback goes away, that may in turn trigger
|
||||
* another callback (if a weak reference to the callback exists) -- running
|
||||
* arbitrary Python code in the middle of gc is a disaster. The convolution
|
||||
* here allows gc to delay triggering such callbacks until the world is in
|
||||
* a sane state again.
|
||||
*/
|
||||
void
|
||||
_PyWeakref_ClearRef(PyWeakReference *self)
|
||||
{
|
||||
PyObject *callback;
|
||||
|
||||
assert(self != NULL);
|
||||
assert(PyWeakref_Check(self));
|
||||
/* Preserve and restore the callback around clear_weakref. */
|
||||
callback = self->wr_callback;
|
||||
self->wr_callback = NULL;
|
||||
clear_weakref(self);
|
||||
self->wr_callback = callback;
|
||||
}
|
||||
|
||||
static void
|
||||
weakref_dealloc(PyObject *self)
|
||||
{
|
||||
PyObject_GC_UnTrack(self);
|
||||
clear_weakref((PyWeakReference *) self);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(self->wr_callback);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
gc_clear(PyWeakReference *self)
|
||||
{
|
||||
clear_weakref(self);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
static char *kwlist[] = {NULL};
|
||||
|
||||
if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) {
|
||||
PyObject *object = PyWeakref_GET_OBJECT(self);
|
||||
Py_INCREF(object);
|
||||
return (object);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static Py_hash_t
|
||||
weakref_hash(PyWeakReference *self)
|
||||
{
|
||||
if (self->hash != -1)
|
||||
return self->hash;
|
||||
if (PyWeakref_GET_OBJECT(self) == Py_None) {
|
||||
PyErr_SetString(PyExc_TypeError, "weak object has gone away");
|
||||
return -1;
|
||||
}
|
||||
self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self));
|
||||
return self->hash;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
weakref_repr(PyWeakReference *self)
|
||||
{
|
||||
PyObject *name, *repr;
|
||||
_Py_IDENTIFIER(__name__);
|
||||
|
||||
if (PyWeakref_GET_OBJECT(self) == Py_None)
|
||||
return PyUnicode_FromFormat("<weakref at %p; dead>", self);
|
||||
|
||||
name = _PyObject_GetAttrId(PyWeakref_GET_OBJECT(self), &PyId___name__);
|
||||
if (name == NULL || !PyUnicode_Check(name)) {
|
||||
if (name == NULL)
|
||||
PyErr_Clear();
|
||||
repr = PyUnicode_FromFormat(
|
||||
"<weakref at %p; to '%s' at %p>",
|
||||
self,
|
||||
Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,
|
||||
PyWeakref_GET_OBJECT(self));
|
||||
}
|
||||
else {
|
||||
repr = PyUnicode_FromFormat(
|
||||
"<weakref at %p; to '%s' at %p (%U)>",
|
||||
self,
|
||||
Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,
|
||||
PyWeakref_GET_OBJECT(self),
|
||||
name);
|
||||
}
|
||||
Py_XDECREF(name);
|
||||
return repr;
|
||||
}
|
||||
|
||||
/* Weak references only support equality, not ordering. Two weak references
|
||||
are equal if the underlying objects are equal. If the underlying object has
|
||||
gone away, they are equal if they are identical. */
|
||||
|
||||
static PyObject *
|
||||
weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
|
||||
{
|
||||
if ((op != Py_EQ && op != Py_NE) ||
|
||||
!PyWeakref_Check(self) ||
|
||||
!PyWeakref_Check(other)) {
|
||||
Py_RETURN_NOTIMPLEMENTED;
|
||||
}
|
||||
if (PyWeakref_GET_OBJECT(self) == Py_None
|
||||
|| PyWeakref_GET_OBJECT(other) == Py_None) {
|
||||
int res = (self == other);
|
||||
if (op == Py_NE)
|
||||
res = !res;
|
||||
if (res)
|
||||
Py_RETURN_TRUE;
|
||||
else
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
return PyObject_RichCompare(PyWeakref_GET_OBJECT(self),
|
||||
PyWeakref_GET_OBJECT(other), op);
|
||||
}
|
||||
|
||||
/* Given the head of an object's list of weak references, extract the
|
||||
* two callback-less refs (ref and proxy). Used to determine if the
|
||||
* shared references exist and to determine the back link for newly
|
||||
* inserted references.
|
||||
*/
|
||||
static void
|
||||
get_basic_refs(PyWeakReference *head,
|
||||
PyWeakReference **refp, PyWeakReference **proxyp)
|
||||
{
|
||||
*refp = NULL;
|
||||
*proxyp = NULL;
|
||||
|
||||
if (head != NULL && head->wr_callback == NULL) {
|
||||
/* We need to be careful that the "basic refs" aren't
|
||||
subclasses of the main types. That complicates this a
|
||||
little. */
|
||||
if (PyWeakref_CheckRefExact(head)) {
|
||||
*refp = head;
|
||||
head = head->wr_next;
|
||||
}
|
||||
if (head != NULL
|
||||
&& head->wr_callback == NULL
|
||||
&& PyWeakref_CheckProxy(head)) {
|
||||
*proxyp = head;
|
||||
/* head = head->wr_next; */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
|
||||
static void
|
||||
insert_after(PyWeakReference *newref, PyWeakReference *prev)
|
||||
{
|
||||
newref->wr_prev = prev;
|
||||
newref->wr_next = prev->wr_next;
|
||||
if (prev->wr_next != NULL)
|
||||
prev->wr_next->wr_prev = newref;
|
||||
prev->wr_next = newref;
|
||||
}
|
||||
|
||||
/* Insert 'newref' at the head of the list; 'list' points to the variable
|
||||
* that stores the head.
|
||||
*/
|
||||
static void
|
||||
insert_head(PyWeakReference *newref, PyWeakReference **list)
|
||||
{
|
||||
PyWeakReference *next = *list;
|
||||
|
||||
newref->wr_prev = NULL;
|
||||
newref->wr_next = next;
|
||||
if (next != NULL)
|
||||
next->wr_prev = newref;
|
||||
*list = newref;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_weakref_init_args(const char *funcname, PyObject *args, PyObject *kwargs,
|
||||
PyObject **obp, PyObject **callbackp)
|
||||
{
|
||||
return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
PyWeakReference *self = NULL;
|
||||
PyObject *ob, *callback = NULL;
|
||||
|
||||
if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) {
|
||||
PyWeakReference *ref, *proxy;
|
||||
PyWeakReference **list;
|
||||
|
||||
if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"cannot create weak reference to '%s' object",
|
||||
Py_TYPE(ob)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
if (callback == Py_None)
|
||||
callback = NULL;
|
||||
list = GET_WEAKREFS_LISTPTR(ob);
|
||||
get_basic_refs(*list, &ref, &proxy);
|
||||
if (callback == NULL && type == &_PyWeakref_RefType) {
|
||||
if (ref != NULL) {
|
||||
/* We can re-use an existing reference. */
|
||||
Py_INCREF(ref);
|
||||
return (PyObject *)ref;
|
||||
}
|
||||
}
|
||||
/* We have to create a new reference. */
|
||||
/* Note: the tp_alloc() can trigger cyclic GC, so the weakref
|
||||
list on ob can be mutated. This means that the ref and
|
||||
proxy pointers we got back earlier may have been collected,
|
||||
so we need to compute these values again before we use
|
||||
them. */
|
||||
self = (PyWeakReference *) (type->tp_alloc(type, 0));
|
||||
if (self != NULL) {
|
||||
init_weakref(self, ob, callback);
|
||||
if (callback == NULL && type == &_PyWeakref_RefType) {
|
||||
insert_head(self, list);
|
||||
}
|
||||
else {
|
||||
PyWeakReference *prev;
|
||||
|
||||
get_basic_refs(*list, &ref, &proxy);
|
||||
prev = (proxy == NULL) ? ref : proxy;
|
||||
if (prev == NULL)
|
||||
insert_head(self, list);
|
||||
else
|
||||
insert_after(self, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
static int
|
||||
weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
PyObject *tmp;
|
||||
|
||||
if (!_PyArg_NoKeywords("ref()", kwargs))
|
||||
return -1;
|
||||
|
||||
if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static PyMemberDef weakref_members[] = {
|
||||
{"__callback__", T_OBJECT, offsetof(PyWeakReference, wr_callback), READONLY},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
PyTypeObject
|
||||
_PyWeakref_RefType = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"weakref",
|
||||
sizeof(PyWeakReference),
|
||||
0,
|
||||
weakref_dealloc, /*tp_dealloc*/
|
||||
0, /*tp_print*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_reserved*/
|
||||
(reprfunc)weakref_repr, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
(hashfunc)weakref_hash, /*tp_hash*/
|
||||
(ternaryfunc)weakref_call, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
0, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
|
||||
| Py_TPFLAGS_BASETYPE, /*tp_flags*/
|
||||
0, /*tp_doc*/
|
||||
(traverseproc)gc_traverse, /*tp_traverse*/
|
||||
(inquiry)gc_clear, /*tp_clear*/
|
||||
(richcmpfunc)weakref_richcompare, /*tp_richcompare*/
|
||||
0, /*tp_weaklistoffset*/
|
||||
0, /*tp_iter*/
|
||||
0, /*tp_iternext*/
|
||||
0, /*tp_methods*/
|
||||
weakref_members, /*tp_members*/
|
||||
0, /*tp_getset*/
|
||||
0, /*tp_base*/
|
||||
0, /*tp_dict*/
|
||||
0, /*tp_descr_get*/
|
||||
0, /*tp_descr_set*/
|
||||
0, /*tp_dictoffset*/
|
||||
weakref___init__, /*tp_init*/
|
||||
PyType_GenericAlloc, /*tp_alloc*/
|
||||
weakref___new__, /*tp_new*/
|
||||
PyObject_GC_Del, /*tp_free*/
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
proxy_checkref(PyWeakReference *proxy)
|
||||
{
|
||||
if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
|
||||
PyErr_SetString(PyExc_ReferenceError,
|
||||
"weakly-referenced object no longer exists");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* If a parameter is a proxy, check that it is still "live" and wrap it,
|
||||
* replacing the original value with the raw object. Raises ReferenceError
|
||||
* if the param is a dead proxy.
|
||||
*/
|
||||
#define UNWRAP(o) \
|
||||
if (PyWeakref_CheckProxy(o)) { \
|
||||
if (!proxy_checkref((PyWeakReference *)o)) \
|
||||
return NULL; \
|
||||
o = PyWeakref_GET_OBJECT(o); \
|
||||
}
|
||||
|
||||
#define UNWRAP_I(o) \
|
||||
if (PyWeakref_CheckProxy(o)) { \
|
||||
if (!proxy_checkref((PyWeakReference *)o)) \
|
||||
return -1; \
|
||||
o = PyWeakref_GET_OBJECT(o); \
|
||||
}
|
||||
|
||||
#define WRAP_UNARY(method, generic) \
|
||||
static PyObject * \
|
||||
method(PyObject *proxy) { \
|
||||
UNWRAP(proxy); \
|
||||
return generic(proxy); \
|
||||
}
|
||||
|
||||
#define WRAP_BINARY(method, generic) \
|
||||
static PyObject * \
|
||||
method(PyObject *x, PyObject *y) { \
|
||||
UNWRAP(x); \
|
||||
UNWRAP(y); \
|
||||
return generic(x, y); \
|
||||
}
|
||||
|
||||
/* Note that the third arg needs to be checked for NULL since the tp_call
|
||||
* slot can receive NULL for this arg.
|
||||
*/
|
||||
#define WRAP_TERNARY(method, generic) \
|
||||
static PyObject * \
|
||||
method(PyObject *proxy, PyObject *v, PyObject *w) { \
|
||||
UNWRAP(proxy); \
|
||||
UNWRAP(v); \
|
||||
if (w != NULL) \
|
||||
UNWRAP(w); \
|
||||
return generic(proxy, v, w); \
|
||||
}
|
||||
|
||||
#define WRAP_METHOD(method, special) \
|
||||
static PyObject * \
|
||||
method(PyObject *proxy) { \
|
||||
_Py_IDENTIFIER(special); \
|
||||
UNWRAP(proxy); \
|
||||
return _PyObject_CallMethodId(proxy, &PyId_##special, NULL); \
|
||||
}
|
||||
|
||||
|
||||
/* direct slots */
|
||||
|
||||
WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
|
||||
WRAP_UNARY(proxy_str, PyObject_Str)
|
||||
WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords)
|
||||
|
||||
static PyObject *
|
||||
proxy_repr(PyWeakReference *proxy)
|
||||
{
|
||||
return PyUnicode_FromFormat(
|
||||
"<weakproxy at %p to %s at %p>",
|
||||
proxy,
|
||||
Py_TYPE(PyWeakref_GET_OBJECT(proxy))->tp_name,
|
||||
PyWeakref_GET_OBJECT(proxy));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
|
||||
{
|
||||
if (!proxy_checkref(proxy))
|
||||
return -1;
|
||||
return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
proxy_richcompare(PyObject *proxy, PyObject *v, int op)
|
||||
{
|
||||
UNWRAP(proxy);
|
||||
UNWRAP(v);
|
||||
return PyObject_RichCompare(proxy, v, op);
|
||||
}
|
||||
|
||||
/* number slots */
|
||||
WRAP_BINARY(proxy_add, PyNumber_Add)
|
||||
WRAP_BINARY(proxy_sub, PyNumber_Subtract)
|
||||
WRAP_BINARY(proxy_mul, PyNumber_Multiply)
|
||||
WRAP_BINARY(proxy_floor_div, PyNumber_FloorDivide)
|
||||
WRAP_BINARY(proxy_true_div, PyNumber_TrueDivide)
|
||||
WRAP_BINARY(proxy_mod, PyNumber_Remainder)
|
||||
WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
|
||||
WRAP_TERNARY(proxy_pow, PyNumber_Power)
|
||||
WRAP_UNARY(proxy_neg, PyNumber_Negative)
|
||||
WRAP_UNARY(proxy_pos, PyNumber_Positive)
|
||||
WRAP_UNARY(proxy_abs, PyNumber_Absolute)
|
||||
WRAP_UNARY(proxy_invert, PyNumber_Invert)
|
||||
WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
|
||||
WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
|
||||
WRAP_BINARY(proxy_and, PyNumber_And)
|
||||
WRAP_BINARY(proxy_xor, PyNumber_Xor)
|
||||
WRAP_BINARY(proxy_or, PyNumber_Or)
|
||||
WRAP_UNARY(proxy_int, PyNumber_Long)
|
||||
WRAP_UNARY(proxy_float, PyNumber_Float)
|
||||
WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
|
||||
WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
|
||||
WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
|
||||
WRAP_BINARY(proxy_ifloor_div, PyNumber_InPlaceFloorDivide)
|
||||
WRAP_BINARY(proxy_itrue_div, PyNumber_InPlaceTrueDivide)
|
||||
WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
|
||||
WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
|
||||
WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
|
||||
WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
|
||||
WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
|
||||
WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
|
||||
WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
|
||||
WRAP_UNARY(proxy_index, PyNumber_Index)
|
||||
|
||||
static int
|
||||
proxy_bool(PyWeakReference *proxy)
|
||||
{
|
||||
PyObject *o = PyWeakref_GET_OBJECT(proxy);
|
||||
if (!proxy_checkref(proxy))
|
||||
return -1;
|
||||
return PyObject_IsTrue(o);
|
||||
}
|
||||
|
||||
static void
|
||||
proxy_dealloc(PyWeakReference *self)
|
||||
{
|
||||
if (self->wr_callback != NULL)
|
||||
PyObject_GC_UnTrack((PyObject *)self);
|
||||
clear_weakref(self);
|
||||
PyObject_GC_Del(self);
|
||||
}
|
||||
|
||||
/* sequence slots */
|
||||
|
||||
static int
|
||||
proxy_contains(PyWeakReference *proxy, PyObject *value)
|
||||
{
|
||||
if (!proxy_checkref(proxy))
|
||||
return -1;
|
||||
return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value);
|
||||
}
|
||||
|
||||
|
||||
/* mapping slots */
|
||||
|
||||
static Py_ssize_t
|
||||
proxy_length(PyWeakReference *proxy)
|
||||
{
|
||||
if (!proxy_checkref(proxy))
|
||||
return -1;
|
||||
return PyObject_Length(PyWeakref_GET_OBJECT(proxy));
|
||||
}
|
||||
|
||||
WRAP_BINARY(proxy_getitem, PyObject_GetItem)
|
||||
|
||||
static int
|
||||
proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
|
||||
{
|
||||
if (!proxy_checkref(proxy))
|
||||
return -1;
|
||||
|
||||
if (value == NULL)
|
||||
return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy), key);
|
||||
else
|
||||
return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value);
|
||||
}
|
||||
|
||||
/* iterator slots */
|
||||
|
||||
static PyObject *
|
||||
proxy_iter(PyWeakReference *proxy)
|
||||
{
|
||||
if (!proxy_checkref(proxy))
|
||||
return NULL;
|
||||
return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
proxy_iternext(PyWeakReference *proxy)
|
||||
{
|
||||
if (!proxy_checkref(proxy))
|
||||
return NULL;
|
||||
return PyIter_Next(PyWeakref_GET_OBJECT(proxy));
|
||||
}
|
||||
|
||||
|
||||
WRAP_METHOD(proxy_bytes, __bytes__)
|
||||
|
||||
|
||||
static PyMethodDef proxy_methods[] = {
|
||||
{"__bytes__", (PyCFunction)proxy_bytes, METH_NOARGS},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
static PyNumberMethods proxy_as_number = {
|
||||
proxy_add, /*nb_add*/
|
||||
proxy_sub, /*nb_subtract*/
|
||||
proxy_mul, /*nb_multiply*/
|
||||
proxy_mod, /*nb_remainder*/
|
||||
proxy_divmod, /*nb_divmod*/
|
||||
proxy_pow, /*nb_power*/
|
||||
proxy_neg, /*nb_negative*/
|
||||
proxy_pos, /*nb_positive*/
|
||||
proxy_abs, /*nb_absolute*/
|
||||
(inquiry)proxy_bool, /*nb_bool*/
|
||||
proxy_invert, /*nb_invert*/
|
||||
proxy_lshift, /*nb_lshift*/
|
||||
proxy_rshift, /*nb_rshift*/
|
||||
proxy_and, /*nb_and*/
|
||||
proxy_xor, /*nb_xor*/
|
||||
proxy_or, /*nb_or*/
|
||||
proxy_int, /*nb_int*/
|
||||
0, /*nb_reserved*/
|
||||
proxy_float, /*nb_float*/
|
||||
proxy_iadd, /*nb_inplace_add*/
|
||||
proxy_isub, /*nb_inplace_subtract*/
|
||||
proxy_imul, /*nb_inplace_multiply*/
|
||||
proxy_imod, /*nb_inplace_remainder*/
|
||||
proxy_ipow, /*nb_inplace_power*/
|
||||
proxy_ilshift, /*nb_inplace_lshift*/
|
||||
proxy_irshift, /*nb_inplace_rshift*/
|
||||
proxy_iand, /*nb_inplace_and*/
|
||||
proxy_ixor, /*nb_inplace_xor*/
|
||||
proxy_ior, /*nb_inplace_or*/
|
||||
proxy_floor_div, /*nb_floor_divide*/
|
||||
proxy_true_div, /*nb_true_divide*/
|
||||
proxy_ifloor_div, /*nb_inplace_floor_divide*/
|
||||
proxy_itrue_div, /*nb_inplace_true_divide*/
|
||||
proxy_index, /*nb_index*/
|
||||
};
|
||||
|
||||
static PySequenceMethods proxy_as_sequence = {
|
||||
(lenfunc)proxy_length, /*sq_length*/
|
||||
0, /*sq_concat*/
|
||||
0, /*sq_repeat*/
|
||||
0, /*sq_item*/
|
||||
0, /*sq_slice*/
|
||||
0, /*sq_ass_item*/
|
||||
0, /*sq_ass_slice*/
|
||||
(objobjproc)proxy_contains, /* sq_contains */
|
||||
};
|
||||
|
||||
static PyMappingMethods proxy_as_mapping = {
|
||||
(lenfunc)proxy_length, /*mp_length*/
|
||||
proxy_getitem, /*mp_subscript*/
|
||||
(objobjargproc)proxy_setitem, /*mp_ass_subscript*/
|
||||
};
|
||||
|
||||
|
||||
PyTypeObject
|
||||
_PyWeakref_ProxyType = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"weakproxy",
|
||||
sizeof(PyWeakReference),
|
||||
0,
|
||||
/* methods */
|
||||
(destructor)proxy_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
(reprfunc)proxy_repr, /* tp_repr */
|
||||
&proxy_as_number, /* tp_as_number */
|
||||
&proxy_as_sequence, /* tp_as_sequence */
|
||||
&proxy_as_mapping, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
proxy_str, /* tp_str */
|
||||
proxy_getattr, /* tp_getattro */
|
||||
(setattrofunc)proxy_setattr, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc)gc_traverse, /* tp_traverse */
|
||||
(inquiry)gc_clear, /* tp_clear */
|
||||
proxy_richcompare, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
(getiterfunc)proxy_iter, /* tp_iter */
|
||||
(iternextfunc)proxy_iternext, /* tp_iternext */
|
||||
proxy_methods, /* tp_methods */
|
||||
};
|
||||
|
||||
|
||||
PyTypeObject
|
||||
_PyWeakref_CallableProxyType = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"weakcallableproxy",
|
||||
sizeof(PyWeakReference),
|
||||
0,
|
||||
/* methods */
|
||||
(destructor)proxy_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
(unaryfunc)proxy_repr, /* tp_repr */
|
||||
&proxy_as_number, /* tp_as_number */
|
||||
&proxy_as_sequence, /* tp_as_sequence */
|
||||
&proxy_as_mapping, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
proxy_call, /* tp_call */
|
||||
proxy_str, /* tp_str */
|
||||
proxy_getattr, /* tp_getattro */
|
||||
(setattrofunc)proxy_setattr, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc)gc_traverse, /* tp_traverse */
|
||||
(inquiry)gc_clear, /* tp_clear */
|
||||
proxy_richcompare, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
(getiterfunc)proxy_iter, /* tp_iter */
|
||||
(iternextfunc)proxy_iternext, /* tp_iternext */
|
||||
};
|
||||
|
||||
|
||||
|
||||
PyObject *
|
||||
PyWeakref_NewRef(PyObject *ob, PyObject *callback)
|
||||
{
|
||||
PyWeakReference *result = NULL;
|
||||
PyWeakReference **list;
|
||||
PyWeakReference *ref, *proxy;
|
||||
|
||||
if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"cannot create weak reference to '%s' object",
|
||||
Py_TYPE(ob)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
list = GET_WEAKREFS_LISTPTR(ob);
|
||||
get_basic_refs(*list, &ref, &proxy);
|
||||
if (callback == Py_None)
|
||||
callback = NULL;
|
||||
if (callback == NULL)
|
||||
/* return existing weak reference if it exists */
|
||||
result = ref;
|
||||
if (result != NULL)
|
||||
Py_INCREF(result);
|
||||
else {
|
||||
/* Note: new_weakref() can trigger cyclic GC, so the weakref
|
||||
list on ob can be mutated. This means that the ref and
|
||||
proxy pointers we got back earlier may have been collected,
|
||||
so we need to compute these values again before we use
|
||||
them. */
|
||||
result = new_weakref(ob, callback);
|
||||
if (result != NULL) {
|
||||
get_basic_refs(*list, &ref, &proxy);
|
||||
if (callback == NULL) {
|
||||
if (ref == NULL)
|
||||
insert_head(result, list);
|
||||
else {
|
||||
/* Someone else added a ref without a callback
|
||||
during GC. Return that one instead of this one
|
||||
to avoid violating the invariants of the list
|
||||
of weakrefs for ob. */
|
||||
Py_DECREF(result);
|
||||
Py_INCREF(ref);
|
||||
result = ref;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PyWeakReference *prev;
|
||||
|
||||
prev = (proxy == NULL) ? ref : proxy;
|
||||
if (prev == NULL)
|
||||
insert_head(result, list);
|
||||
else
|
||||
insert_after(result, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (PyObject *) result;
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
|
||||
{
|
||||
PyWeakReference *result = NULL;
|
||||
PyWeakReference **list;
|
||||
PyWeakReference *ref, *proxy;
|
||||
|
||||
if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"cannot create weak reference to '%s' object",
|
||||
Py_TYPE(ob)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
list = GET_WEAKREFS_LISTPTR(ob);
|
||||
get_basic_refs(*list, &ref, &proxy);
|
||||
if (callback == Py_None)
|
||||
callback = NULL;
|
||||
if (callback == NULL)
|
||||
/* attempt to return an existing weak reference if it exists */
|
||||
result = proxy;
|
||||
if (result != NULL)
|
||||
Py_INCREF(result);
|
||||
else {
|
||||
/* Note: new_weakref() can trigger cyclic GC, so the weakref
|
||||
list on ob can be mutated. This means that the ref and
|
||||
proxy pointers we got back earlier may have been collected,
|
||||
so we need to compute these values again before we use
|
||||
them. */
|
||||
result = new_weakref(ob, callback);
|
||||
if (result != NULL) {
|
||||
PyWeakReference *prev;
|
||||
|
||||
if (PyCallable_Check(ob))
|
||||
Py_TYPE(result) = &_PyWeakref_CallableProxyType;
|
||||
else
|
||||
Py_TYPE(result) = &_PyWeakref_ProxyType;
|
||||
get_basic_refs(*list, &ref, &proxy);
|
||||
if (callback == NULL) {
|
||||
if (proxy != NULL) {
|
||||
/* Someone else added a proxy without a callback
|
||||
during GC. Return that one instead of this one
|
||||
to avoid violating the invariants of the list
|
||||
of weakrefs for ob. */
|
||||
Py_DECREF(result);
|
||||
Py_INCREF(result = proxy);
|
||||
goto skip_insert;
|
||||
}
|
||||
prev = ref;
|
||||
}
|
||||
else
|
||||
prev = (proxy == NULL) ? ref : proxy;
|
||||
|
||||
if (prev == NULL)
|
||||
insert_head(result, list);
|
||||
else
|
||||
insert_after(result, prev);
|
||||
skip_insert:
|
||||
;
|
||||
}
|
||||
}
|
||||
return (PyObject *) result;
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
PyWeakref_GetObject(PyObject *ref)
|
||||
{
|
||||
if (ref == NULL || !PyWeakref_Check(ref)) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
return PyWeakref_GET_OBJECT(ref);
|
||||
}
|
||||
|
||||
/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
|
||||
* handle_weakrefs().
|
||||
*/
|
||||
static void
|
||||
handle_callback(PyWeakReference *ref, PyObject *callback)
|
||||
{
|
||||
PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL);
|
||||
|
||||
if (cbresult == NULL)
|
||||
PyErr_WriteUnraisable(callback);
|
||||
else
|
||||
Py_DECREF(cbresult);
|
||||
}
|
||||
|
||||
/* This function is called by the tp_dealloc handler to clear weak references.
|
||||
*
|
||||
* This iterates through the weak references for 'object' and calls callbacks
|
||||
* for those references which have one. It returns when all callbacks have
|
||||
* been attempted.
|
||||
*/
|
||||
void
|
||||
PyObject_ClearWeakRefs(PyObject *object)
|
||||
{
|
||||
PyWeakReference **list;
|
||||
|
||||
if (object == NULL
|
||||
|| !PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))
|
||||
|| object->ob_refcnt != 0) {
|
||||
PyErr_BadInternalCall();
|
||||
return;
|
||||
}
|
||||
list = GET_WEAKREFS_LISTPTR(object);
|
||||
/* Remove the callback-less basic and proxy references */
|
||||
if (*list != NULL && (*list)->wr_callback == NULL) {
|
||||
clear_weakref(*list);
|
||||
if (*list != NULL && (*list)->wr_callback == NULL)
|
||||
clear_weakref(*list);
|
||||
}
|
||||
if (*list != NULL) {
|
||||
PyWeakReference *current = *list;
|
||||
Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
|
||||
PyObject *err_type, *err_value, *err_tb;
|
||||
|
||||
PyErr_Fetch(&err_type, &err_value, &err_tb);
|
||||
if (count == 1) {
|
||||
PyObject *callback = current->wr_callback;
|
||||
|
||||
current->wr_callback = NULL;
|
||||
clear_weakref(current);
|
||||
if (callback != NULL) {
|
||||
if (((PyObject *)current)->ob_refcnt > 0)
|
||||
handle_callback(current, callback);
|
||||
Py_DECREF(callback);
|
||||
}
|
||||
}
|
||||
else {
|
||||
PyObject *tuple;
|
||||
Py_ssize_t i = 0;
|
||||
|
||||
tuple = PyTuple_New(count * 2);
|
||||
if (tuple == NULL) {
|
||||
_PyErr_ChainExceptions(err_type, err_value, err_tb);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
PyWeakReference *next = current->wr_next;
|
||||
|
||||
if (((PyObject *)current)->ob_refcnt > 0)
|
||||
{
|
||||
Py_INCREF(current);
|
||||
PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
|
||||
PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
|
||||
}
|
||||
else {
|
||||
Py_DECREF(current->wr_callback);
|
||||
}
|
||||
current->wr_callback = NULL;
|
||||
clear_weakref(current);
|
||||
current = next;
|
||||
}
|
||||
for (i = 0; i < count; ++i) {
|
||||
PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
|
||||
|
||||
/* The tuple may have slots left to NULL */
|
||||
if (callback != NULL) {
|
||||
PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
|
||||
handle_callback((PyWeakReference *)item, callback);
|
||||
}
|
||||
}
|
||||
Py_DECREF(tuple);
|
||||
}
|
||||
assert(!PyErr_Occurred());
|
||||
PyErr_Restore(err_type, err_value, err_tb);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue