python-3.6.zip added from Github

README.cosmo contains the necessary links.
This commit is contained in:
ahgamut 2021-08-08 09:38:33 +05:30 committed by Justine Tunney
parent 75fc601ff5
commit 0c4c56ff39
4219 changed files with 1968626 additions and 0 deletions

1
third_party/python/Objects/README vendored Normal file
View file

@ -0,0 +1 @@
Source files for various builtin objects

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
View 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
View 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 }
};

File diff suppressed because it is too large Load diff

View 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

File diff suppressed because it is too large Load diff

324
third_party/python/Objects/capsule.c vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

1638
third_party/python/Objects/descrobject.c vendored Normal file

File diff suppressed because it is too large Load diff

View 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
View 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

File diff suppressed because it is too large Load diff

431
third_party/python/Objects/enumobject.c vendored Normal file
View 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

File diff suppressed because it is too large Load diff

531
third_party/python/Objects/fileobject.c vendored Normal file
View 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

File diff suppressed because it is too large Load diff

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

File diff suppressed because it is too large Load diff

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
View 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

File diff suppressed because it is too large Load diff

755
third_party/python/Objects/listsort.txt vendored Normal file
View 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.

View 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

File diff suppressed because it is too large Load diff

3114
third_party/python/Objects/memoryobject.c vendored Normal file

File diff suppressed because it is too large Load diff

View 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));
}

View 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 */
};

View 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

File diff suppressed because it is too large Load diff

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

File diff suppressed because it is too large Load diff

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

File diff suppressed because it is too large Load diff

671
third_party/python/Objects/sliceobject.c vendored Normal file
View 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 */
};

View 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

View 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

View 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

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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

View 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 */

View 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

View 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);
}
}

View 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;
}

View 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;
}
}

View 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;
}

View 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 */

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load diff

View 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
View 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

File diff suppressed because it is too large Load diff

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
View 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
View 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()

View 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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View 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);
}
}